2 # -*- coding: iso-8859-15 -*-
6 This module contains functions that convert winterrodeln specific strings (like geographic coordinates) from string
7 to appropriate python types and the other way round.
8 Functions that take strings to convert it to python types are called *_from_str(value, [...]) and are supposed to
9 validate the string. In case of errors, a ValueError (or a subclass thereof) is returned.
10 Functions that take python types and convert it to Winterrodeln strings are called *_to_str(value, [...]) and can
11 assume that the value they get is valid. If it is not, the behavior is undefined.
12 The namedtuple FromToConverter groups corresponding *_from_str and *_to_str converters.
14 import email.headerregistry
17 from collections import OrderedDict, namedtuple
19 import mwparserfromhell
21 from wrpylib.mwmarkup import template_to_table
24 # FromToConverter type
25 # --------------------
27 # namedtuple that groups corresponding *_from_str and *_to_str functions.
28 FromToConverter = namedtuple('FromToConverter', ['from_str', 'to_str'])
34 def opt_from_str(value, from_str, empty=None):
35 """Makes the converter `from_str` "optional"
36 by replacing the empty string with a predefined value (default: None)."""
37 return empty if value == '' else from_str(value)
40 def opt_to_str(value, to_str, empty=None):
41 return '' if value == empty else to_str(value)
47 def no_german_from_str(value, from_str, use_tuple=True, no_value=None):
48 """Makes it possible to have "Nein" as special value. If use_tuple is True, a tuple is returned. The first
49 entry of the tuple is False in case the value is "Nein", otherwiese the first value is True. The second value is
50 no_value in case of the value being "Nein", otherwise it is the result of from_str(value).
51 If use_tuple is False, no_value is returned in case the value is "Nein", otherwise the result of from_str(value)."""
53 return (False, no_value) if use_tuple else no_value
54 return (True, from_str(value)) if use_tuple else from_str(value)
57 def no_german_to_str(value, to_str, use_tuple=True, no_value=None):
61 return to_str(value[1])
68 # "optional"/"no" converter
69 # -------------------------
71 def opt_no_german_from_str(value, from_str, use_tuple=True, no_value=None, empty=(None, None)):
72 return opt_from_str(value, lambda v: no_german_from_str(v, from_str, use_tuple, no_value), empty)
75 def opt_no_german_to_str(value, to_str, use_tuple=True, no_value=None, empty=(None, None)):
76 return opt_to_str(value, lambda v: no_german_to_str(v, to_str, use_tuple, no_value), empty)
82 def choice_from_str(value, choices):
83 """Returns the value if it is a member of the choices iterable."""
84 if value not in choices:
85 raise ValueError('{} is an invalid value')
92 def dictkey_from_str(value, key_str_dict):
93 """Returns the key of an entry in the key_str_dict if the value of the entry corresponds to the given value."""
95 return dict(list(zip(key_str_dict.values(), key_str_dict.keys())))[value]
97 raise ValueError("Invalid value '{}'".format(value))
100 def dictkey_to_str(value, key_str_dict):
102 return key_str_dict[value]
104 raise ValueError("Invalid value '{}'".format(value))
107 # enum/"list" converter
108 # ---------------------
110 def enum_from_str(value, from_str, separator=';', min_len=0):
111 """Semicolon separated list of entries with the same "type"."""
112 values = value.split(separator)
113 if len(values) == 1 and values[0] == '':
115 if len(values) < min_len:
116 raise ValueError('at least {} entry/entries have to be in the enumeration'.format(min_len))
117 return list(map(from_str, map(str.strip, values)))
120 def enum_to_str(value, to_str, separator='; '):
121 return separator.join(map(to_str, value))
124 # value/comment converter
125 # -----------------------
127 def value_comment_from_str(value, value_from_str, comment_from_str, comment_optional=False):
128 """Makes it possible to have a mandatory comment in parenthesis at the end of the string."""
131 comment_end_pos = None
132 for i, char in enumerate(value[::-1]):
135 if open_brackets == 1:
137 if len(value[-1-comment_end_pos:].rstrip()) > 1:
138 raise ValueError('invalid characters after comment')
141 if open_brackets == 0:
142 comment = value[-i:-1-comment_end_pos]
143 value = value[:-i-1].rstrip()
146 if open_brackets > 0:
147 raise ValueError('bracket mismatch')
148 if not comment_optional:
149 raise ValueError('mandatory comment not found')
150 return value_from_str(value), comment_from_str(comment)
153 def value_comment_to_str(value, value_to_str, comment_to_str, comment_optional=False):
154 left = value_to_str(value[0])
155 comment = comment_to_str(value[1])
156 if len(comment) > 0 or not comment_optional:
157 comment = '({})'.format(comment)
160 if len(comment) == 0:
162 return '{} {}'.format(left, comment)
168 def str_from_str(value):
169 """Converter that takes any string and returns it as string without validation.
170 In other words, this function does nothing and just returns its argument."""
174 def str_to_str(value):
178 def req_str_from_str(value):
180 raise ValueError('missing required value')
181 return str_from_str(value)
184 def opt_str_from_str(value):
185 return opt_from_str(value, str_from_str)
188 def opt_str_to_str(value):
189 return opt_to_str(value, str_to_str)
192 opt_str_converter = FromToConverter(opt_str_from_str, opt_str_to_str)
195 # optional no or string converter
196 # -------------------------------
198 def opt_no_or_str_from_str(value):
200 'Nein' => (False, None); 'Nur Wochenende' => (True, 'Nur Wochenende'); 'Ja' => (True, 'Ja'); '' => (None, None)"""
201 return opt_no_german_from_str(value, req_str_from_str)
204 def opt_no_or_str_to_str(value):
205 return opt_no_german_to_str(value, str_to_str)
208 opt_no_or_str_converter = FromToConverter(opt_no_or_str_from_str, opt_no_or_str_to_str)
214 def int_from_str(value, min=None, max=None):
215 """Converter that takes a string representation of an integer and returns the integer.
216 :param value: string representation of an integer
217 :param min: If not None, the integer has to be at least min
218 :param max: If not None, the integer has to be no more than max
221 if min is not None and value < min:
222 raise ValueError('{} must be >= than {}'.format(value, min))
223 if max is not None and value > max:
224 raise ValueError('{} must be <= than {}'.format(value, max))
228 def int_to_str(value):
232 def opt_int_from_str(value, min=None, max=None):
233 return opt_from_str(value, lambda val: int_from_str(val, min, max))
236 def opt_int_to_str(value):
237 return opt_to_str(value, int_to_str)
240 def opt_uint_from_str(value, min=0, max=None):
241 """Optional positive integer."""
242 return opt_int_from_str(value, min, max)
245 def opt_uint_to_str(value):
246 return opt_int_to_str(value)
249 opt_uint_converter = FromToConverter(opt_uint_from_str, opt_uint_to_str)
255 BOOL_GERMAN = OrderedDict([(False, 'Nein'), (True, 'Ja')])
258 def bool_german_from_str(value):
259 return dictkey_from_str(value, BOOL_GERMAN)
262 def bool_german_to_str(value):
263 return dictkey_to_str(value, BOOL_GERMAN)
266 def opt_bool_german_from_str(value):
267 return opt_from_str(value, bool_german_from_str)
270 def opt_bool_german_to_str(value):
271 return opt_to_str(value, bool_german_to_str)
274 opt_bool_german_converter = FromToConverter(opt_bool_german_from_str, opt_bool_german_to_str)
280 TRISTATE_GERMAN = OrderedDict([(0.0, 'Nein'), (0.5, 'Teilweise'), (1.0, 'Ja')])
283 def tristate_german_from_str(value):
284 return dictkey_from_str(value, TRISTATE_GERMAN)
287 def tristate_german_to_str(value):
288 return dictkey_to_str(value, TRISTATE_GERMAN)
291 def opt_tristate_german_from_str(value):
292 return opt_from_str(value, tristate_german_from_str)
295 def opt_tristate_german_to_str(value):
296 return opt_to_str(value, tristate_german_to_str)
299 opt_tristate_german_converter = FromToConverter(opt_tristate_german_from_str, opt_tristate_german_to_str)
302 # tristate with comment converter
303 # -------------------------------
305 def opt_tristate_german_comment_from_str(value):
306 """Ja, Nein or Vielleicht, optionally with comment in parenthesis."""
307 return value_comment_from_str(value, opt_tristate_german_from_str, opt_str_from_str, True)
310 def opt_tristate_german_comment_to_str(value):
311 return value_comment_to_str(value, opt_tristate_german_to_str, opt_str_to_str, True)
314 opt_tristate_german_comment_converter = FromToConverter(opt_tristate_german_comment_from_str, opt_tristate_german_comment_to_str)
320 def url_from_str(value):
321 result = urllib.parse.urlparse(value)
322 if result.scheme not in ['http', 'https']:
323 raise ValueError('scheme has to be http or https')
324 if not result.netloc:
325 raise ValueError('url does not contain netloc')
329 def url_to_str(value):
333 # webauskunft converter
334 # ---------------------
336 def webauskunft_from_str(value):
337 return opt_no_german_from_str(value, url_from_str)
340 def webauskunft_to_str(value):
341 return opt_no_german_to_str(value, url_to_str)
344 webauskunft_converter = FromToConverter(webauskunft_from_str, webauskunft_to_str)
350 def wikipage_from_str(value):
351 """Validates wiki page name like '[[Birgitzer Alm]]'.
352 The page is not checked for existance.
353 An empty string is an error.
354 '[[Birgitzer Alm]]' => '[[Birgitzer Alm]]'
356 if not value.startswith('[[') or not value.endswith(']]'):
357 raise ValueError('No valid wiki page name "{}"'.format(value))
361 def wikipage_to_str(value):
365 def opt_wikipage_enum_from_str(value):
366 """Validates a list of wiki pages like '[[Birgitzer Alm]]; [[Kemater Alm]]'.
367 '[[Birgitzer Alm]]; [[Kemater Alm]]' => ['[[Birgitzer Alm]]', '[[Kemater Alm]]']
368 '[[Birgitzer Alm]]' => ['[[Birgitzer Alm]]']
372 return opt_no_german_from_str(value, lambda val: enum_from_str(val, wikipage_from_str), False, [], None)
375 def opt_wikipage_enum_to_str(value):
376 return opt_no_german_to_str(value, lambda val: enum_to_str(val, wikipage_to_str), False, [], None)
379 opt_wikipage_enum_converter = FromToConverter(opt_wikipage_enum_from_str, opt_wikipage_enum_to_str)
385 def email_from_str(value):
386 """Takes an email address like 'office@example.com', checks it for correctness and returns it again as string."""
388 email.headerregistry.Address(addr_spec=value)
389 except email.errors.HeaderParseError as e:
390 raise ValueError('Invalid email address: {}'.format(value), e)
394 def email_to_str(value):
398 def masked_email_from_str(value, mask='(at)', masked_only=False):
399 """Converts an email address that is possibly masked. Returns a tuple. The first parameter is the un-masked
400 email address as string, the second is a boolean telling whether the address was masked."""
401 unmasked = value.replace(mask, '@')
402 was_masked = unmasked != value
403 if masked_only and not was_masked:
404 raise ValueError('E-Mail address not masked')
405 return email_from_str(unmasked), was_masked
408 def masked_email_to_str(value, mask='(at)'):
409 """Value is a tuple. The first entry is the email address, the second one is a boolean telling whether the
410 email address should be masked."""
411 email, do_masking = value
412 email = email_to_str(email)
414 email = email.replace('@', mask)
418 def emails_from_str(value):
419 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)
422 def emails_to_str(value):
423 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)
426 emails_converter = FromToConverter(emails_from_str, emails_to_str)
432 def phone_number_from_str(value):
433 match = re.match(r'\+\d+(-\d+)*$', value)
435 raise ValueError('invalid format of phone number - use something like +43-699-1234567')
439 def phone_number_to_str(value):
443 def opt_phone_comment_enum_from_str(value, comment_optional=False):
444 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)
447 def opt_phone_comment_enum_to_str(value, comment_optional=False):
448 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)
451 opt_phone_comment_enum_converter = FromToConverter(opt_phone_comment_enum_from_str, opt_phone_comment_enum_to_str)
454 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))
457 # longitude/latitude converter
458 # ----------------------------
460 LonLat = namedtuple('LonLat', ['lon', 'lat'])
463 lonlat_none = LonLat(None, None)
466 def lonlat_from_str(value):
467 """Converts a winterrodeln geo string like '47.076207 N 11.453553 E' (being '<latitude> N <longitude> E'
468 to the LonLat(lon, lat) named tupel."""
469 r = re.match('(\d+\.\d+) N (\d+\.\d+) E', value)
470 if r is None: raise ValueError("Coordinates '{}' have not a format like '47.076207 N 11.453553 E'".format(value))
471 return LonLat(float(r.groups()[1]), float(r.groups()[0]))
474 def lonlat_to_str(value):
475 return '{:.6f} N {:.6f} E'.format(value.lat, value.lon)
478 def opt_lonlat_from_str(value):
479 return opt_from_str(value, lonlat_from_str, lonlat_none)
482 def opt_lonlat_to_str(value):
483 return opt_to_str(value, lonlat_to_str, lonlat_none)
486 opt_lonlat_converter = FromToConverter(opt_lonlat_from_str, opt_lonlat_to_str)
489 # difficulty converter
490 # --------------------
492 DIFFICULTY_GERMAN = OrderedDict([(1, 'leicht'), (2, 'mittel'), (3, 'schwer')])
495 def difficulty_german_from_str(value):
496 return dictkey_from_str(value, DIFFICULTY_GERMAN)
499 def difficulty_german_to_str(value):
500 return dictkey_to_str(value, DIFFICULTY_GERMAN)
503 def opt_difficulty_german_from_str(value):
504 return opt_from_str(value, difficulty_german_from_str)
507 def opt_difficulty_german_to_str(value):
508 return opt_to_str(value, difficulty_german_to_str)
511 opt_difficulty_german_converter = FromToConverter(opt_difficulty_german_from_str, opt_difficulty_german_to_str)
514 # avalanches converter
515 # --------------------
517 AVALANCHES_GERMAN = OrderedDict([(1, 'kaum'), (2, 'selten'), (3, 'gelegentlich'), (4, 'häufig')])
520 def avalanches_german_from_str(value):
521 return dictkey_from_str(value, AVALANCHES_GERMAN)
524 def avalanches_german_to_str(value):
525 return dictkey_to_str(value, AVALANCHES_GERMAN)
528 def opt_avalanches_german_from_str(value):
529 return opt_from_str(value, avalanches_german_from_str)
532 def opt_avalanches_german_to_str(value):
533 return opt_to_str(value, avalanches_german_to_str)
536 opt_avalanches_german_converter = FromToConverter(opt_avalanches_german_from_str, opt_avalanches_german_to_str)
542 LIFT_GERMAN = ['Sessellift', 'Gondel', 'Linienbus', 'Taxi', 'Sonstige']
545 def lift_german_from_str(value):
546 """Checks a lift_details property. It is a value comment property with the following
553 Alternatively, the value u'Nein' is allowed.
554 An empty string maps to (None, None).
559 'Sessellift <=> [('Sessellift', None)]
560 'Gondel (nur bis zur Hälfte)' <=> [('Gondel', 'nur bis zur Hälfte')]
561 'Sessellift; Taxi' <=> [('Sessellift', None), ('Taxi', None)]
562 'Sessellift (Wochenende); Taxi (6 Euro)' <=> [('Sessellift', 'Wochenende'), ('Taxi', '6 Euro')]
564 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)
567 def lift_german_to_str(value):
568 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)
571 lift_german_converter = FromToConverter(lift_german_from_str, lift_german_to_str)
574 # public transport converter
575 # --------------------------
577 PUBLIC_TRANSPORT_GERMAN = OrderedDict([(1, 'Sehr gut'), (2, 'Gut'), (3, 'Mittelmäßig'), (4, 'Schlecht'), (5, 'Nein'), (6, 'Ja')])
580 def public_transport_german_from_str(value):
581 return dictkey_from_str(value, PUBLIC_TRANSPORT_GERMAN)
584 def public_transport_german_to_str(value):
585 return dictkey_to_str(value, PUBLIC_TRANSPORT_GERMAN)
588 def opt_public_transport_german_from_str(value):
589 return opt_from_str(value, public_transport_german_from_str)
592 def opt_public_transport_german_to_str(value):
593 return opt_to_str(value, public_transport_german_to_str)
596 opt_public_transport_german_converter = FromToConverter(opt_public_transport_german_from_str, opt_public_transport_german_to_str)
602 CACHET_REGEXP = [r'(Tiroler Naturrodelbahn-Gütesiegel) ([12]\d{3}) (leicht|mittel|schwer)$']
605 def single_cachet_german_from_str(value):
606 for pattern in CACHET_REGEXP:
607 match = re.match(pattern, value)
609 return match.groups()
610 raise ValueError("'{}' is no valid cachet".format(value))
613 def single_cachet_german_to_str(value):
614 return ' '.join(value)
617 def cachet_german_from_str(value):
618 """Converts a "Gütesiegel":
621 'Tiroler Naturrodelbahn-Gütesiegel 2009 mittel' => [('Tiroler Naturrodelbahn-Gütesiegel', '2009', 'mittel')]"""
622 return opt_no_german_from_str(value, lambda val: enum_from_str(val, single_cachet_german_from_str), False, [], None)
625 def cachet_german_to_str(value):
626 return opt_no_german_to_str(value, lambda val: enum_to_str(val, single_cachet_german_to_str), False, [], None)
629 cachet_german_converter = FromToConverter(cachet_german_from_str, cachet_german_to_str)
632 # night light days converter
633 # --------------------------
635 def nightlightdays_from_str(value):
636 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)
639 def nightlightdays_to_str(value):
640 return value_comment_to_str(value, lambda val: opt_to_str(val, int_to_str), opt_str_to_str, comment_optional=True)
643 nightlightdays_converter = FromToConverter(nightlightdays_from_str, nightlightdays_to_str)
646 # string with optional comment enum/list converter
647 # ------------------------------------------------
649 def opt_str_opt_comment_enum_from_str(value):
650 """The value can be an empty string, 'Nein' or a semicolon-separated list of strings with optional comments.
653 'Talstation (nur mit Ticket); Schneealm' => [('Talstation', 'nur mit Ticket'), ('Schneealm', None)]"""
654 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)
657 def opt_str_opt_comment_enum_to_str(value):
658 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)
661 opt_str_opt_comment_enum_converter = FromToConverter(opt_str_opt_comment_enum_from_str, opt_str_opt_comment_enum_to_str)
667 class ValueErrorList(ValueError):
671 def wikibox_from_template(template, name, converter_dict):
672 if template.name.strip() != name:
673 raise ValueError('Box name has to be "{}"'.format(name))
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(name)
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, name, 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 return wikibox_from_template(template, RODELBAHNBOX_TEMPLATE_NAME, RODELBAHNBOX_DICT)
756 def rodelbahnbox_to_template(value):
757 return wikibox_to_template(value, RODELBAHNBOX_TEMPLATE_NAME, RODELBAHNBOX_DICT)
760 def rodelbahnbox_from_str(value):
761 return wikibox_from_str(value, RODELBAHNBOX_TEMPLATE_NAME, RODELBAHNBOX_DICT)
764 def rodelbahnbox_to_str(value):
765 template = rodelbahnbox_to_template(value)
766 template_to_table(template, 20)
770 # Gasthausbox converter
771 # ---------------------
773 GASTHAUSBOX_TEMPLATE_NAME = 'Gasthausbox'
776 GASTHAUSBOX_DICT = OrderedDict([
777 ('Position', opt_lonlat_converter), # '47.583333 N 15.75 E'
778 ('Höhe', opt_uint_converter),
779 ('Betreiber', opt_str_converter),
780 ('Sitzplätze', opt_uint_converter),
781 ('Übernachtung', opt_no_or_str_converter),
782 ('Rauchfrei', opt_tristate_german_converter),
783 ('Rodelverleih', opt_no_or_str_converter),
784 ('Handyempfang', opt_str_opt_comment_enum_converter),
785 ('Homepage', webauskunft_converter),
786 ('E-Mail', emails_converter),
787 ('Telefon', opt_phone_comment_opt_enum_converter),
788 ('Bild', opt_str_converter),
789 ('Rodelbahnen', opt_wikipage_enum_converter)])
792 def gasthausbox_from_template(template):
793 return wikibox_from_template(template, GASTHAUSBOX_TEMPLATE_NAME, GASTHAUSBOX_DICT)
796 def gasthausbox_to_template(value):
797 return wikibox_to_template(value, GASTHAUSBOX_TEMPLATE_NAME, GASTHAUSBOX_DICT)
800 def gasthausbox_from_str(value):
801 return wikibox_from_str(value, GASTHAUSBOX_TEMPLATE_NAME, GASTHAUSBOX_DICT)
804 def gasthausbox_to_str(value):
805 template = gasthausbox_to_template(value)
806 template_to_table(template, 17)
810 # Helper function to make page title pretty
811 # -----------------------------------------
813 def sledrun_page_title_to_pretty_url(page_title):
814 """Converts a page_title from the page_title column of wrsledruncache to name_url.
815 name_url is not used by MediaWiki but by new applications like wrweb."""
816 return page_title.lower().replace(' ', '-').replace('_', '-').replace('(', '').replace(')', '')