Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/validators/i18n/fi.py: 66%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

35 statements  

1"""Finland.""" 

2 

3# standard 

4from datetime import date 

5from functools import lru_cache 

6import re 

7 

8# local 

9from validators.utils import validator 

10 

11 

12@lru_cache 

13def _business_id_pattern(): 

14 """Business ID Pattern.""" 

15 return re.compile(r"^[0-9]{7}-[0-9]$") 

16 

17 

18@lru_cache 

19def _ssn_pattern(ssn_check_marks: str): 

20 """SSN Pattern.""" 

21 return re.compile( 

22 r"""^ 

23 (?P<date>(0[1-9]|[1-2]\d|3[01]) 

24 (0[1-9]|1[012]) 

25 (\d{{2}})) 

26 (?P<century>[ABCDEFYXWVU+-]) 

27 (?P<serial>(\d{{3}})) 

28 (?P<checksum>[{check_marks}])$""".format(check_marks=ssn_check_marks), 

29 re.VERBOSE | re.ASCII, 

30 ) 

31 

32 

33@validator 

34def fi_business_id(value: str, /): 

35 """Validate a Finnish Business ID. 

36 

37 Each company in Finland has a distinct business id. For more 

38 information see [Finnish Trade Register][1] 

39 

40 [1]: http://en.wikipedia.org/wiki/Finnish_Trade_Register 

41 

42 Examples: 

43 >>> fi_business_id('0112038-9') # Fast Monkeys Ltd 

44 True 

45 >>> fi_business_id('1234567-8') # Bogus ID 

46 ValidationError(func=fi_business_id, args={'value': '1234567-8'}) 

47 

48 Args: 

49 value: 

50 Business ID string to be validated. 

51 

52 Returns: 

53 (Literal[True]): If `value` is a valid finnish business id. 

54 (ValidationError): If `value` is an invalid finnish business id. 

55 """ 

56 if not value: 

57 return False 

58 if not re.fullmatch(_business_id_pattern(), value): 

59 return False 

60 factors = [7, 9, 10, 5, 8, 4, 2] 

61 numbers = map(int, value[:7]) 

62 checksum = int(value[8]) 

63 modulo = sum(f * n for f, n in zip(factors, numbers)) % 11 

64 return (11 - modulo == checksum) or (modulo == checksum == 0) 

65 

66 

67@validator 

68def fi_ssn(value: str, /, *, allow_temporal_ssn: bool = True): 

69 """Validate a Finnish Social Security Number. 

70 

71 This validator is based on [django-localflavor-fi][1]. 

72 

73 [1]: https://github.com/django/django-localflavor-fi/ 

74 

75 Examples: 

76 >>> fi_ssn('010101-0101') 

77 True 

78 >>> fi_ssn('101010-0102') 

79 ValidationError(func=fi_ssn, args={'value': '101010-0102'}) 

80 

81 Args: 

82 value: 

83 Social Security Number to be validated. 

84 allow_temporal_ssn: 

85 Whether to accept temporal SSN numbers. Temporal SSN numbers are the 

86 ones where the serial is in the range [900-999]. By default temporal 

87 SSN numbers are valid. 

88 

89 Returns: 

90 (Literal[True]): If `value` is a valid finnish SSN. 

91 (ValidationError): If `value` is an invalid finnish SSN. 

92 """ 

93 if not value: 

94 return False 

95 ssn_check_marks = "0123456789ABCDEFHJKLMNPRSTUVWXY" 

96 if not (result := re.fullmatch(_ssn_pattern(ssn_check_marks), value)): 

97 return False 

98 gd = result.groupdict() 

99 century = 1800 if gd["century"] == "+" else 2000 if gd["century"] in "ABCDEF" else 1900 

100 birth_date = gd["date"] 

101 date(century + int(birth_date[4:]), int(birth_date[2:4]), int(birth_date[:2])) 

102 checksum = int(gd["date"] + gd["serial"]) 

103 return ( 

104 int(gd["serial"]) >= 2 

105 and (allow_temporal_ssn or int(gd["serial"]) <= 899) 

106 and ssn_check_marks[checksum % len(ssn_check_marks)] == gd["checksum"] 

107 )