-#!/usr/bin/python3.4
-# -*- coding: utf-8 -*-
-# $Id$
-# $HeadURL$
"""
This module contains functions that convert winterrodeln specific strings (like geographic coordinates) from string
to appropriate python types and the other way round.
import urllib.parse
import re
from collections import OrderedDict, namedtuple
+from email.errors import HeaderParseError
+from typing import Tuple, Optional, List, Callable, Union, TypeVar, Dict, NamedTuple
-import mwparserfromhell
+import mwparserfromhell # https://github.com/earwig/mwparserfromhell
+from mwparserfromhell.nodes import Template
from wrpylib.mwmarkup import format_template_table
+T = TypeVar("T") # use for generic type annotations
+E = TypeVar("E") # use for generic type annotations
+N = TypeVar("N") # use for generic type annotations
+
+
# FromToConverter type
# --------------------
# optional converter
# ------------------
-def opt_from_str(value, from_str, empty=None):
+def opt_from_str(value: str, from_str: Callable[[str], T], empty: E = None) -> Union[T, E]:
"""Makes the converter `from_str` "optional"
by replacing the empty string with a predefined value (default: None)."""
return empty if value == '' else from_str(value)
-def opt_to_str(value, to_str, empty=None):
+def opt_to_str(value: Union[T, E], to_str: Callable[[T], str], empty: E = None) -> str:
return '' if value == empty else to_str(value)
# "no" converter
# --------------
-def no_german_from_str(value, from_str, use_tuple=True, no_value=None):
+def no_german_from_str(value: str, from_str: Callable[[str], T], use_tuple: bool = True, no_value: N = None) \
+ -> Union[Tuple[bool, Union[T, N]], T, N]:
"""Makes it possible to have "Nein" as special value. If use_tuple is True, a tuple is returned. The first
- entry of the tuple is False in case the value is "Nein", otherwiese the first value is True. The second value is
+ entry of the tuple is False in case the value is "Nein", otherwise the first value is True. The second value is
no_value in case of the value being "Nein", otherwise it is the result of from_str(value).
If use_tuple is False, no_value is returned in case the value is "Nein", otherwise the result of from_str(value)."""
if value == 'Nein':
return (True, from_str(value)) if use_tuple else from_str(value)
-def no_german_to_str(value, to_str, use_tuple=True, no_value=None):
+def no_german_to_str(value: Union[Tuple[bool, Union[T, N]], T, N], to_str: Callable[[T], str], use_tuple: bool = True,
+ no_value: N = None) -> str:
if use_tuple:
if not value[0]:
return 'Nein'
# "optional"/"no" converter
# -------------------------
-def opt_no_german_from_str(value, from_str, use_tuple=True, no_value=None, empty=(None, None)):
+def opt_no_german_from_str(value: str, from_str: Callable[[str], T], use_tuple: bool = True, no_value: N = None,
+ empty: E = (None, None)) -> Union[Tuple[bool, Union[T, N]], T, N, E]:
+ """
+ 'abc' -> (True, from_str('abc')) or from_str('abc')
+ 'Nein' -> (False, no_value) or no_value
+ '' -> empty
+ """
return opt_from_str(value, lambda v: no_german_from_str(v, from_str, use_tuple, no_value), empty)
-def opt_no_german_to_str(value, to_str, use_tuple=True, no_value=None, empty=(None, None)):
+def opt_no_german_to_str(value: Union[Tuple[bool, Union[T, N]], T, N, E], to_str: Callable[[T], str], use_tuple=True,
+ no_value: N = None, empty: E = (None, None)) -> str:
+ """
+ (True, 'abc') -> to_value('abc')
+ (False, no_value) -> 'Nein'
+ empty -> ''
+ """
return opt_to_str(value, lambda v: no_german_to_str(v, to_str, use_tuple, no_value), empty)
def choice_from_str(value, choices):
"""Returns the value if it is a member of the choices iterable."""
if value not in choices:
- raise ValueError('{} is an invalid value')
+ raise ValueError(f"'{value}' is an invalid value")
return value
# dictkey converter
# -----------------
-def dictkey_from_str(value, key_str_dict):
+def dictkey_from_str(value: str, key_str_dict: Dict[T, str]) -> T:
"""Returns the key of an entry in the key_str_dict if the value of the entry corresponds to the given value."""
try:
return dict(list(zip(key_str_dict.values(), key_str_dict.keys())))[value]
except KeyError:
- raise ValueError("Invalid value '{}'".format(value))
+ raise ValueError(f"Invalid value '{value}'")
-def dictkey_to_str(value, key_str_dict):
+def dictkey_to_str(value: T, key_str_dict: Dict[T, str]) -> str:
try:
return key_str_dict[value]
except KeyError:
- raise ValueError("Invalid value '{}'".format(value))
+ raise ValueError(f"Invalid value '{value}'")
# enum/"list" converter
# ---------------------
-def enum_from_str(value, from_str, separator=';', min_len=0):
+def enum_from_str(value: str, from_str: Callable[[str], T], separator: str = ';', min_len: int = 0) -> List[T]:
"""Semicolon separated list of entries with the same "type"."""
values = value.split(separator)
if len(values) == 1 and values[0] == '':
values = []
if len(values) < min_len:
- raise ValueError('at least {} entry/entries have to be in the enumeration'.format(min_len))
+ raise ValueError(f'at least {min_len} entry/entries have to be in the enumeration')
return list(map(from_str, map(str.strip, values)))
-def enum_to_str(value, to_str, separator='; '):
+def enum_to_str(value: List[T], to_str: Callable[[T], str], separator='; ') -> str:
return separator.join(map(to_str, value))
# value/comment converter
# -----------------------
-def value_comment_from_str(value, value_from_str, comment_from_str, comment_optional=False):
+def value_comment_from_str(value: str, value_from_str: Callable[[str], T], comment_from_str: Callable[[str], E],
+ comment_optional: bool = False) -> Tuple[T, E]:
"""Makes it possible to have a mandatory comment in parenthesis at the end of the string."""
comment = ''
if value.endswith(')'):
raise ValueError('mandatory comment not found')
else:
if not comment_optional:
- raise ValueError('mandatory comment not found in "{}"'.format(value))
+ raise ValueError(f'mandatory comment not found in "{value}"')
return value_from_str(value), comment_from_str(comment)
-def value_comment_to_str(value, value_to_str, comment_to_str, comment_optional=False):
+def value_comment_to_str(value: Tuple[T, E], value_to_str: Callable[[T], str], comment_to_str: Callable[[E], str],
+ comment_optional: bool = False) -> str:
left = value_to_str(value[0])
comment = comment_to_str(value[1])
if len(comment) > 0 or not comment_optional:
- comment = '({})'.format(comment)
+ comment = f'({comment})'
if len(left) == 0:
return comment
if len(comment) == 0:
return left
- return '{} {}'.format(left, comment)
+ return f'{left} {comment}'
# string converter
# ----------------
-def str_from_str(value):
+def str_from_str(value: str) -> str:
"""Converter that takes any string and returns it as string without validation.
In other words, this function does nothing and just returns its argument."""
return value
-def str_to_str(value):
+def str_to_str(value: str) -> str:
return value
-def req_str_from_str(value):
+def req_str_from_str(value: str) -> str:
if value == '':
raise ValueError('missing required value')
return str_from_str(value)
-def opt_str_from_str(value):
+def opt_str_from_str(value: str) -> Optional[str]:
return opt_from_str(value, str_from_str)
-def opt_str_to_str(value):
+def opt_str_to_str(value: Optional[str]) -> str:
return opt_to_str(value, str_to_str)
# optional no or string converter
# -------------------------------
-def opt_no_or_str_from_str(value):
+def opt_no_or_str_from_str(value: str) -> Tuple[Optional[bool], Optional[str]]:
"""
'Nein' => (False, None); 'Nur Wochenende' => (True, 'Nur Wochenende'); 'Ja' => (True, 'Ja'); '' => (None, None)"""
return opt_no_german_from_str(value, req_str_from_str)
-def opt_no_or_str_to_str(value):
+def opt_no_or_str_to_str(value: Tuple[Optional[bool], Optional[str]]) -> str:
return opt_no_german_to_str(value, str_to_str)
# integer converter
# -----------------
-def int_from_str(value, min=None, max=None):
+def int_from_str(value: str, minimum: Optional[int] = None, maximum: Optional[int] = None) -> int:
"""Converter that takes a string representation of an integer and returns the integer.
:param value: string representation of an integer
- :param min: If not None, the integer has to be at least min
- :param max: If not None, the integer has to be no more than max
+ :param minimum: If not None, the integer has to be at least min
+ :param maximum: If not None, the integer has to be no more than max
"""
value = int(value)
- if min is not None and value < min:
- raise ValueError('{} must be >= than {}'.format(value, min))
- if max is not None and value > max:
- raise ValueError('{} must be <= than {}'.format(value, max))
+ if minimum is not None and value < minimum:
+ raise ValueError(f'{value} must be >= than {minimum}')
+ if maximum is not None and value > maximum:
+ raise ValueError(f'{value} must be <= than {maximum}')
return value
-def int_to_str(value):
+def int_to_str(value: int) -> str:
return str(value)
-def opt_int_from_str(value, min=None, max=None):
- return opt_from_str(value, lambda val: int_from_str(val, min, max))
+def opt_int_from_str(value: str, minimum: Optional[int] = None, maximum: Optional[int] = None) -> Optional[int]:
+ return opt_from_str(value, lambda val: int_from_str(val, minimum, maximum))
-def opt_int_to_str(value):
+def opt_int_to_str(value: Optional[int]) -> str:
return opt_to_str(value, int_to_str)
-def opt_uint_from_str(value, min=0, max=None):
+def opt_uint_from_str(value: str, minimum: int = 0, maximum: Optional[int] = None) -> Optional[int]:
"""Optional positive integer."""
- return opt_int_from_str(value, min, max)
+ return opt_int_from_str(value, minimum, maximum)
-def opt_uint_to_str(value):
+def opt_uint_to_str(value: Optional[int]) -> str:
return opt_int_to_str(value)
BOOL_GERMAN = OrderedDict([(False, 'Nein'), (True, 'Ja')])
-def bool_german_from_str(value):
+def bool_german_from_str(value: str) -> bool:
return dictkey_from_str(value, BOOL_GERMAN)
-def bool_german_to_str(value):
+def bool_german_to_str(value: bool) -> str:
return dictkey_to_str(value, BOOL_GERMAN)
-def opt_bool_german_from_str(value):
+def opt_bool_german_from_str(value: str) -> Optional[bool]:
return opt_from_str(value, bool_german_from_str)
-def opt_bool_german_to_str(value):
+def opt_bool_german_to_str(value: Optional[bool]) -> str:
return opt_to_str(value, bool_german_to_str)
TRISTATE_GERMAN = OrderedDict([(0.0, 'Nein'), (0.5, 'Teilweise'), (1.0, 'Ja')])
-def tristate_german_from_str(value):
+def tristate_german_from_str(value: str) -> float:
return dictkey_from_str(value, TRISTATE_GERMAN)
-def tristate_german_to_str(value):
+def tristate_german_to_str(value: float) -> str:
return dictkey_to_str(value, TRISTATE_GERMAN)
-def opt_tristate_german_from_str(value):
+def opt_tristate_german_from_str(value: str) -> Optional[float]:
return opt_from_str(value, tristate_german_from_str)
-def opt_tristate_german_to_str(value):
+def opt_tristate_german_to_str(value: Optional[float]) -> str:
return opt_to_str(value, tristate_german_to_str)
# tristate with comment converter
# -------------------------------
-def opt_tristate_german_comment_from_str(value):
- """Ja, Nein or Vielleicht, optionally with comment in parenthesis."""
+def opt_tristate_german_comment_from_str(value: str) -> Tuple[Optional[float], Optional[str]]:
+ """Ja, Nein or Teilweise, optionally with comment in parenthesis."""
return value_comment_from_str(value, opt_tristate_german_from_str, opt_str_from_str, True)
-def opt_tristate_german_comment_to_str(value):
+def opt_tristate_german_comment_to_str(value: Tuple[Optional[float], Optional[str]]) -> str:
return value_comment_to_str(value, opt_tristate_german_to_str, opt_str_to_str, True)
-opt_tristate_german_comment_converter = FromToConverter(opt_tristate_german_comment_from_str, opt_tristate_german_comment_to_str)
+opt_tristate_german_comment_converter = FromToConverter(opt_tristate_german_comment_from_str,
+ opt_tristate_german_comment_to_str)
# url converter
# -------------
-def url_from_str(value):
+def url_from_str(value: str) -> str:
result = urllib.parse.urlparse(value)
if result.scheme not in ['http', 'https']:
raise ValueError('scheme has to be http or https')
return value
-def url_to_str(value):
+def url_to_str(value: str) -> str:
return value
# webauskunft converter
# ---------------------
-def webauskunft_from_str(value):
+def webauskunft_from_str(value: str) -> Tuple[Optional[bool], Optional[str]]:
+ """Converts a URL or 'Nein' to a tuple
+ 'http://www.example.com/' -> (True, 'http://www.example.com/')
+ 'Nein' -> (False, None)
+ '' -> (None, None)
+
+ :param value: URL or 'Nein'
+ :return: tuple
+ """
return opt_no_german_from_str(value, url_from_str)
-def webauskunft_to_str(value):
+def webauskunft_to_str(value: Tuple[Optional[bool], Optional[str]]) -> str:
return opt_no_german_to_str(value, url_to_str)
# wikipage converter
# ------------------
-def wikipage_from_str(value):
+def wikipage_from_str(value: str) -> str:
"""Validates wiki page name like '[[Birgitzer Alm]]'.
- The page is not checked for existance.
+ The page is not checked for existence.
An empty string is an error.
'[[Birgitzer Alm]]' => '[[Birgitzer Alm]]'
"""
- if not value.startswith('[[') or not value.endswith(']]'):
- raise ValueError('No valid wiki page name "{}"'.format(value))
+ if re.match(r'\[\[[^\[\]]+]]$', value) is None:
+ raise ValueError(f'No valid wiki page name "{value}"')
return value
-def wikipage_to_str(value):
+def wikipage_to_str(value: str) -> str:
return value
-def opt_wikipage_enum_from_str(value):
+def opt_wikipage_enum_from_str(value: str) -> Optional[List[str]]:
"""Validates a list of wiki pages like '[[Birgitzer Alm]]; [[Kemater Alm]]'.
'[[Birgitzer Alm]]; [[Kemater Alm]]' => ['[[Birgitzer Alm]]', '[[Kemater Alm]]']
'[[Birgitzer Alm]]' => ['[[Birgitzer Alm]]']
return opt_no_german_from_str(value, lambda val: enum_from_str(val, wikipage_from_str), False, [], None)
-def opt_wikipage_enum_to_str(value):
+def opt_wikipage_enum_to_str(value: Optional[List[str]]) -> str:
return opt_no_german_to_str(value, lambda val: enum_to_str(val, wikipage_to_str), False, [], None)
# email converter
# ---------------
-def email_from_str(value):
+def email_from_str(value: str) -> str:
"""Takes an email address like 'office@example.com', checks it for correctness and returns it again as string."""
try:
email.headerregistry.Address(addr_spec=value)
- except email.errors.HeaderParseError as e:
- raise ValueError('Invalid email address: {}'.format(value), e)
+ except HeaderParseError as e:
+ raise ValueError(f'Invalid email address: {value}', e)
return value
-def email_to_str(value):
+def email_to_str(value: str) -> str:
return str(value)
-def masked_email_from_str(value, mask='(at)', masked_only=False):
+def masked_email_from_str(value: str, mask='(at)', masked_only=False) -> Tuple[str, bool]:
"""Converts an email address that is possibly masked. Returns a tuple. The first parameter is the un-masked
email address as string, the second is a boolean telling whether the address was masked."""
unmasked = value.replace(mask, '@')
return email_from_str(unmasked), was_masked
-def masked_email_to_str(value, mask='(at)'):
+def masked_email_to_str(value: Tuple[str, bool], mask='(at)') -> str:
"""Value is a tuple. The first entry is the email address, the second one is a boolean telling whether the
email address should be masked."""
- email, do_masking = value
- email = email_to_str(email)
+ email_, do_masking = value
+ email_ = email_to_str(email_)
if do_masking:
- email = email.replace('@', mask)
- return email
+ email_ = email_.replace('@', mask)
+ return email_
-def emails_from_str(value):
- return opt_no_german_from_str(value, lambda val: enum_from_str(val, lambda v: value_comment_from_str(v, masked_email_from_str, opt_str_from_str, True)), False, [], None)
+def emails_from_str(value: str) -> Optional[List[Tuple[str, str]]]:
+ return opt_no_german_from_str(
+ value,
+ lambda val:
+ enum_from_str(val, lambda v: value_comment_from_str(v, masked_email_from_str, opt_str_from_str, True)),
+ False, [], None)
-def emails_to_str(value):
- return opt_no_german_to_str(value, lambda val: enum_to_str(val, lambda v: value_comment_to_str(v, masked_email_to_str, opt_str_to_str, True)), False, [], None)
+def emails_to_str(value: Optional[List[Tuple[str, str]]]) -> str:
+ 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)
emails_converter = FromToConverter(emails_from_str, emails_to_str)
# phone converter
# ---------------
-def phone_number_from_str(value):
+def phone_number_from_str(value: str) -> str:
match = re.match(r'\+\d+(-\d+)*$', value)
if match is None:
raise ValueError('invalid format of phone number - use something like +43-699-1234567')
return value
-def phone_number_to_str(value):
+def phone_number_to_str(value: str) -> str:
return value
-def opt_phone_comment_enum_from_str(value, comment_optional=False):
- return opt_no_german_from_str(value, lambda val: enum_from_str(val, lambda v: value_comment_from_str(v, phone_number_from_str, opt_str_from_str if comment_optional else req_str_from_str, comment_optional)), False, [], None)
+def opt_phone_comment_enum_from_str(value: str, comment_optional: bool = False) -> Optional[List[Tuple[str, str]]]:
+ 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)
-def opt_phone_comment_enum_to_str(value, comment_optional=False):
- return opt_no_german_to_str(value, lambda val: enum_to_str(val, lambda v: value_comment_to_str(v, phone_number_to_str, opt_str_to_str if comment_optional else str_to_str, comment_optional)), False, [], None)
+def opt_phone_comment_enum_to_str(value: Optional[List[Tuple[str, str]]], comment_optional: bool = False) -> str:
+ 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)
opt_phone_comment_enum_converter = FromToConverter(opt_phone_comment_enum_from_str, opt_phone_comment_enum_to_str)
-opt_phone_comment_opt_enum_converter = FromToConverter(lambda value: opt_phone_comment_enum_from_str(value, True), lambda value: opt_phone_comment_enum_to_str(value, True))
+opt_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))
# longitude/latitude converter
# ----------------------------
-LonLat = namedtuple('LonLat', ['lon', 'lat'])
-
+class LonLat(NamedTuple):
+ lon: float
+ lat: float
-lonlat_none = LonLat(None, None)
-
-def lonlat_from_str(value):
- """Converts a winterrodeln geo string like '47.076207 N 11.453553 E' (being '<latitude> N <longitude> E'
- to the LonLat(lon, lat) named tupel."""
- r = re.match('(\d+\.\d+) N (\d+\.\d+) E', value)
- if r is None: raise ValueError("Coordinates '{}' have not a format like '47.076207 N 11.453553 E'".format(value))
+def lonlat_from_str(value: str) -> LonLat:
+ """Converts a Winterrodeln geo string like '47.076207 N 11.453553 E' (being '<latitude> N <longitude> E'
+ to the LonLat(lon, lat) named tuple."""
+ r = re.match(r'(\d+\.\d+) N (\d+\.\d+) E', value)
+ if r is None:
+ raise ValueError(f"Coordinates '{value}' have not a format like '47.076207 N 11.453553 E'")
return LonLat(float(r.groups()[1]), float(r.groups()[0]))
-def lonlat_to_str(value):
- return '{:.6f} N {:.6f} E'.format(value.lat, value.lon)
+def lonlat_to_str(value: LonLat) -> str:
+ return f'{value.lat:.6f} N {value.lon:.6f} E'
-def opt_lonlat_from_str(value):
- return opt_from_str(value, lonlat_from_str, lonlat_none)
+def opt_lonlat_from_str(value: str) -> Optional[LonLat]:
+ return opt_from_str(value, lonlat_from_str, None)
-def opt_lonlat_to_str(value):
- return opt_to_str(value, lonlat_to_str, lonlat_none)
+def opt_lonlat_to_str(value: Optional[LonLat]) -> str:
+ return opt_to_str(value, lonlat_to_str, None)
opt_lonlat_converter = FromToConverter(opt_lonlat_from_str, opt_lonlat_to_str)
DIFFICULTY_GERMAN = OrderedDict([(1, 'leicht'), (2, 'mittel'), (3, 'schwer')])
-def difficulty_german_from_str(value):
+def difficulty_german_from_str(value: str) -> int:
return dictkey_from_str(value, DIFFICULTY_GERMAN)
-def difficulty_german_to_str(value):
+def difficulty_german_to_str(value: int) -> str:
return dictkey_to_str(value, DIFFICULTY_GERMAN)
-def opt_difficulty_german_from_str(value):
+def opt_difficulty_german_from_str(value: str) -> Optional[int]:
return opt_from_str(value, difficulty_german_from_str)
-def opt_difficulty_german_to_str(value):
+def opt_difficulty_german_to_str(value: Optional[int]) -> str:
return opt_to_str(value, difficulty_german_to_str)
AVALANCHES_GERMAN = OrderedDict([(1, 'kaum'), (2, 'selten'), (3, 'gelegentlich'), (4, 'häufig')])
-def avalanches_german_from_str(value):
+def avalanches_german_from_str(value: str) -> int:
return dictkey_from_str(value, AVALANCHES_GERMAN)
-def avalanches_german_to_str(value):
+def avalanches_german_to_str(value: int) -> str:
return dictkey_to_str(value, AVALANCHES_GERMAN)
-def opt_avalanches_german_from_str(value):
+def opt_avalanches_german_from_str(value: str) -> Optional[int]:
return opt_from_str(value, avalanches_german_from_str)
-def opt_avalanches_german_to_str(value):
+def opt_avalanches_german_to_str(value: Optional[int]) -> str:
return opt_to_str(value, avalanches_german_to_str)
LIFT_GERMAN = ['Sessellift', 'Gondel', 'Linienbus', 'Taxi', 'Sonstige']
-def lift_german_from_str(value):
+def lift_german_from_str(value) -> Optional[List[Tuple[str, Optional[str]]]]:
"""Checks a lift_details property. It is a value comment property with the following
values allowed:
'Sessellift'
'Sessellift; Taxi' <=> [('Sessellift', None), ('Taxi', None)]
'Sessellift (Wochenende); Taxi (6 Euro)' <=> [('Sessellift', 'Wochenende'), ('Taxi', '6 Euro')]
"""
- return opt_no_german_from_str(value, lambda value_enum: enum_from_str(value_enum, lambda value_comment: value_comment_from_str(value_comment, lambda v: choice_from_str(v, LIFT_GERMAN), opt_str_from_str, comment_optional=True)), use_tuple=False, no_value=[], empty=None)
-
-
-def lift_german_to_str(value):
- return opt_no_german_to_str(value, lambda value_enum: enum_to_str(value_enum, lambda value_comment: value_comment_to_str(value_comment, str_to_str, opt_str_to_str, comment_optional=True)), use_tuple=False, no_value=[], empty=None)
+ return opt_no_german_from_str(
+ value,
+ lambda value_enum:
+ enum_from_str(
+ value_enum,
+ lambda value_comment:
+ value_comment_from_str(
+ value_comment,
+ lambda v: choice_from_str(v, LIFT_GERMAN),
+ opt_str_from_str,
+ comment_optional=True)
+ ), use_tuple=False, no_value=[], empty=None)
+
+
+def lift_german_to_str(value: Optional[List[Tuple[str, Optional[str]]]]) -> str:
+ 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)
lift_german_converter = FromToConverter(lift_german_from_str, lift_german_to_str)
# public transport converter
# --------------------------
-PUBLIC_TRANSPORT_GERMAN = OrderedDict([(1, 'Sehr gut'), (2, 'Gut'), (3, 'Mittelmäßig'), (4, 'Schlecht'), (5, 'Nein'), (6, 'Ja')])
+PUBLIC_TRANSPORT_GERMAN = OrderedDict(
+ [(1, 'Sehr gut'), (2, 'Gut'), (3, 'Mittelmäßig'), (4, 'Schlecht'), (5, 'Nein'), (6, 'Ja')])
-def public_transport_german_from_str(value):
+def public_transport_german_from_str(value: str) -> int:
return dictkey_from_str(value, PUBLIC_TRANSPORT_GERMAN)
-def public_transport_german_to_str(value):
+def public_transport_german_to_str(value: int) -> str:
return dictkey_to_str(value, PUBLIC_TRANSPORT_GERMAN)
-def opt_public_transport_german_from_str(value):
+def opt_public_transport_german_from_str(value: str) -> Optional[int]:
return opt_from_str(value, public_transport_german_from_str)
-def opt_public_transport_german_to_str(value):
+def opt_public_transport_german_to_str(value: Optional[int]) -> str:
return opt_to_str(value, public_transport_german_to_str)
-opt_public_transport_german_converter = FromToConverter(opt_public_transport_german_from_str, opt_public_transport_german_to_str)
+opt_public_transport_german_converter = FromToConverter(opt_public_transport_german_from_str,
+ opt_public_transport_german_to_str)
# cachet converter
CACHET_REGEXP = [r'(Tiroler Naturrodelbahn-Gütesiegel) ([12]\d{3}) (leicht|mittel|schwer)$']
-def single_cachet_german_from_str(value):
+def single_cachet_german_from_str(value: str) -> Tuple[str, str, str]:
for pattern in CACHET_REGEXP:
- match = re.match(pattern, value)
- if match:
- return match.groups()
- raise ValueError("'{}' is no valid cachet".format(value))
+ match_ = re.match(pattern, value)
+ if match_:
+ return match_.groups()
+ raise ValueError(f"'{value}' is no valid cachet")
-def single_cachet_german_to_str(value):
+def single_cachet_german_to_str(value: Tuple[str, str, str]) -> str:
return ' '.join(value)
-def cachet_german_from_str(value):
+def cachet_german_from_str(value) -> Optional[List[Tuple[str, str, str]]]:
"""Converts a "Gütesiegel":
'' => None
'Nein' => []
# night light days converter
# --------------------------
-def nightlightdays_from_str(value):
- return value_comment_from_str(value, lambda val: opt_from_str(val, lambda v: int_from_str(v, min=0, max=7)), opt_str_from_str, comment_optional=True)
+def nightlightdays_from_str(value: str) -> Tuple[int, Optional[str]]:
+ return value_comment_from_str(
+ value,
+ lambda val:
+ opt_from_str(val, lambda v: int_from_str(v, minimum=0, maximum=7)), opt_str_from_str, comment_optional=True)
-def nightlightdays_to_str(value):
+def nightlightdays_to_str(value: Tuple[int, Optional[str]]) -> str:
return value_comment_to_str(value, lambda val: opt_to_str(val, int_to_str), opt_str_to_str, comment_optional=True)
# string with optional comment enum/list converter
# ------------------------------------------------
-def opt_str_opt_comment_enum_from_str(value):
+def opt_str_opt_comment_enum_from_str(value: str) -> Optional[List[Tuple[str, Optional[str]]]]:
"""The value can be an empty string, 'Nein' or a semicolon-separated list of strings with optional comments.
'' => None
'Nein' => []
'Talstation (nur mit Ticket); Schneealm' => [('Talstation', 'nur mit Ticket'), ('Schneealm', None)]"""
- return opt_no_german_from_str(value, lambda val: enum_from_str(val, lambda v: value_comment_from_str(v, req_str_from_str, opt_str_from_str, True)), False, [], None)
-
-
-def opt_str_opt_comment_enum_to_str(value):
- return opt_no_german_to_str(value, lambda val: enum_to_str(val, lambda v: value_comment_to_str(v, str_to_str, opt_str_to_str, True)), False, [], None)
+ return opt_no_german_from_str(
+ value,
+ lambda val:
+ enum_from_str(
+ val,
+ lambda v:
+ value_comment_from_str(v, req_str_from_str, opt_str_from_str, True)
+ ), False, [], None)
+
+
+def opt_str_opt_comment_enum_to_str(value: Optional[List[Tuple[str, Optional[str]]]]) -> str:
+ return opt_no_german_to_str(
+ value,
+ lambda val:
+ enum_to_str(
+ val, lambda v:
+ value_comment_to_str(v, str_to_str, opt_str_to_str, True)
+ ), False, [], None)
opt_str_opt_comment_enum_converter = FromToConverter(opt_str_opt_comment_enum_from_str, opt_str_opt_comment_enum_to_str)
pass
-def wikibox_from_template(template, name, converter_dict):
- if template.name.strip() != name:
- raise ValueError('Box name has to be "{}"'.format(name))
+def wikibox_from_template(template: Template, converter_dict: dict) -> dict:
+ """Returns an ordered dict."""
result = OrderedDict()
exceptions_dict = OrderedDict()
# check values
for key, converter in converter_dict.items():
try:
if not template.has(key):
- raise ValueError('Missing parameter "{}"'.format(key))
+ raise ValueError(f'Missing parameter "{key}"')
result[key] = converter.from_str(str(template.get(key).value.strip()))
except ValueError as e:
exceptions_dict[key] = e
# check if keys are superfluous
superfluous_keys = {str(p.name.strip()) for p in template.params} - set(converter_dict.keys())
for key in superfluous_keys:
- exceptions_dict[key] = ValueError('Superfluous parameter: "{}"'.format(key))
+ exceptions_dict[key] = ValueError(f'Superfluous parameter: "{key}"')
if len(exceptions_dict) > 0:
- raise ValueErrorList('{} error(s) occurred when parsing template parameters.'.format(len(exceptions_dict)), exceptions_dict)
+ raise ValueErrorList(f'{len(exceptions_dict)} error(s) occurred when parsing template parameters.',
+ exceptions_dict)
return result
-def wikibox_to_template(value, name, converter_dict):
- template = mwparserfromhell.nodes.template.Template(name)
+def wikibox_to_template(value: dict, name: str, converter_dict: dict) -> Template:
+ template = Template(name)
for key, converter in converter_dict.items():
template.add(key, converter.to_str(value[key]))
return template
-def template_from_str(value, name):
+def template_from_str(value: str, name: str) -> Template:
wikicode = mwparserfromhell.parse(value)
- template_list = wikicode.filter_templates(name)
- if len(name) == 0:
- raise ValueError('No "{}" template was found'.format(name))
+ template_list = wikicode.filter_templates(recursive=False, matches=lambda t: t.name.strip() == name)
+ if len(template_list) == 0:
+ raise ValueError(f'No "{name}" template was found')
if len(template_list) > 1:
- raise ValueError('{} "{}" templates were found'.format(len(template_list), name))
+ raise ValueError(f'{len(template_list)} "{name}" templates were found')
return template_list[0]
-def wikibox_from_str(value, name, converter_dict):
+def wikibox_from_str(value: str, name: str, converter_dict: dict) -> dict:
template = template_from_str(value, name)
- return wikibox_from_template(template, name, converter_dict)
+ return wikibox_from_template(template, converter_dict)
-def wikibox_to_str(value, name, converter_dict):
+def wikibox_to_str(value: dict, name: str, converter_dict: dict) -> str:
return str(wikibox_to_template(value, name, converter_dict))
RODELBAHNBOX_DICT = OrderedDict([
- ('Position', opt_lonlat_converter), # '47.583333 N 15.75 E'
- ('Position oben', opt_lonlat_converter), # '47.583333 N 15.75 E'
- ('Höhe oben', opt_uint_converter), # '2000'
- ('Position unten', opt_lonlat_converter), # '47.583333 N 15.75 E'
- ('Höhe unten', opt_uint_converter), # '1200'
- ('Länge', opt_uint_converter), # 3500
- ('Schwierigkeit', opt_difficulty_german_converter), # 'mittel'
- ('Lawinen', opt_avalanches_german_converter), # 'kaum'
- ('Betreiber', opt_str_converter), # 'Max Mustermann'
- ('Öffentliche Anreise', opt_public_transport_german_converter), # 'Mittelmäßig'
- ('Aufstieg möglich', opt_bool_german_converter), # 'Ja'
- ('Aufstieg getrennt', opt_tristate_german_comment_converter), # 'Ja'
- ('Gehzeit', opt_uint_converter), # 90
- ('Aufstiegshilfe', lift_german_converter), # 'Gondel (unterer Teil)'
+ ('Position', opt_lonlat_converter), # '47.583333 N 15.75 E'
+ ('Position oben', opt_lonlat_converter), # '47.583333 N 15.75 E'
+ ('Höhe oben', opt_uint_converter), # '2000'
+ ('Position unten', opt_lonlat_converter), # '47.583333 N 15.75 E'
+ ('Höhe unten', opt_uint_converter), # '1200'
+ ('Länge', opt_uint_converter), # 3500
+ ('Schwierigkeit', opt_difficulty_german_converter), # 'mittel'
+ ('Lawinen', opt_avalanches_german_converter), # 'kaum'
+ ('Betreiber', opt_no_or_str_converter), # 'Max Mustermann'
+ ('Öffentliche Anreise', opt_public_transport_german_converter), # 'Mittelmäßig'
+ ('Aufstieg möglich', opt_bool_german_converter), # 'Ja'
+ ('Aufstieg getrennt', opt_tristate_german_comment_converter), # 'Ja'
+ ('Gehzeit', opt_uint_converter), # 90
+ ('Aufstiegshilfe', lift_german_converter), # 'Gondel (unterer Teil)'
('Beleuchtungsanlage', opt_tristate_german_comment_converter),
- ('Beleuchtungstage', nightlightdays_converter), # '3 (Montag, Mittwoch, Freitag)'
- ('Rodelverleih', opt_str_opt_comment_enum_converter), # 'Talstation Serlesbahnan'
- ('Gütesiegel', cachet_german_converter), # 'Tiroler Naturrodelbahn-Gütesiegel 2009 mittel'
- ('Webauskunft', webauskunft_converter), # 'http://www.nösslachhütte.at/page9.php'
- ('Telefonauskunft', opt_phone_comment_enum_converter), # '+43-664-5487520 (Mitterer Alm)'
+ ('Beleuchtungstage', nightlightdays_converter), # '3 (Montag, Mittwoch, Freitag)'
+ ('Rodelverleih', opt_str_opt_comment_enum_converter), # 'Talstation Serlesbahnan'
+ ('Gütesiegel', cachet_german_converter), # 'Tiroler Naturrodelbahn-Gütesiegel 2009 mittel'
+ ('Webauskunft', webauskunft_converter), # 'http://www.nösslachhütte.at/page9.php'
+ ('Telefonauskunft', opt_phone_comment_enum_converter), # '+43-664-5487520 (Mitterer Alm)'
('Bild', opt_str_converter),
('In Übersichtskarte', opt_bool_german_converter),
('Forumid', opt_uint_converter)
])
-def rodelbahnbox_from_template(template):
- return wikibox_from_template(template, RODELBAHNBOX_TEMPLATE_NAME, RODELBAHNBOX_DICT)
+def rodelbahnbox_from_template(template: Template) -> dict:
+ """Returns an ordered dict."""
+ return wikibox_from_template(template, RODELBAHNBOX_DICT)
-def rodelbahnbox_to_template(value):
+def rodelbahnbox_to_template(value: dict) -> Template:
return wikibox_to_template(value, RODELBAHNBOX_TEMPLATE_NAME, RODELBAHNBOX_DICT)
-def rodelbahnbox_from_str(value):
+def rodelbahnbox_from_str(value: str) -> Dict:
+ """Returns an ordered dict."""
return wikibox_from_str(value, RODELBAHNBOX_TEMPLATE_NAME, RODELBAHNBOX_DICT)
-def rodelbahnbox_to_str(value):
+def rodelbahnbox_to_str(value: Dict) -> str:
template = rodelbahnbox_to_template(value)
format_template_table(template, 20)
return str(template)
GASTHAUSBOX_DICT = OrderedDict([
- ('Position', opt_lonlat_converter), # '47.583333 N 15.75 E'
+ ('Position', opt_lonlat_converter), # '47.583333 N 15.75 E'
('Höhe', opt_uint_converter),
('Betreiber', opt_str_converter),
('Sitzplätze', opt_uint_converter),
('Rodelbahnen', opt_wikipage_enum_converter)])
-def gasthausbox_from_template(template):
- return wikibox_from_template(template, GASTHAUSBOX_TEMPLATE_NAME, GASTHAUSBOX_DICT)
+def gasthausbox_from_template(template: Template) -> dict:
+ """Returns an ordered dict."""
+ return wikibox_from_template(template, GASTHAUSBOX_DICT)
-def gasthausbox_to_template(value):
+def gasthausbox_to_template(value: dict) -> Template:
return wikibox_to_template(value, GASTHAUSBOX_TEMPLATE_NAME, GASTHAUSBOX_DICT)
-def gasthausbox_from_str(value):
+def gasthausbox_from_str(value: str) -> dict:
+ """Returns an ordered dict."""
return wikibox_from_str(value, GASTHAUSBOX_TEMPLATE_NAME, GASTHAUSBOX_DICT)
-def gasthausbox_to_str(value):
+def gasthausbox_to_str(value: dict) -> str:
template = gasthausbox_to_template(value)
format_template_table(template, 17)
return str(template)
# Helper function to make page title pretty
# -----------------------------------------
-def sledrun_page_title_to_pretty_url(page_title):
+def sledrun_page_title_to_pretty_url(page_title: str) -> str:
"""Converts a page_title from the page_title column of wrsledruncache to name_url.
name_url is not used by MediaWiki but by new applications like wrweb."""
return page_title.lower().replace(' ', '-').replace('_', '-').replace('(', '').replace(')', '')