Skip to content

Commit 9e54c72

Browse files
quantuskvesteri
authored andcommitted
Improve fi-ssn validator (python-validators#97)
* Fi-ssn validator: checksum must be upper case * Fi-ssn validator: better validation for the date * Fi-ssn validator: Implement serial validation Make fi-ssn validator by default accept all valid serials, meaning serials in range 2 - 999. Also add an option to not allow temporal serials that are in the range 900 - 999.
1 parent 1a0e1bb commit 9e54c72

File tree

2 files changed

+27
-6
lines changed

2 files changed

+27
-6
lines changed

tests/i18n/test_fi.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@ def test_returns_failed_validation_on_invalid_email(value):
2525

2626

2727
@pytest.mark.parametrize(('value',), [
28+
('010190-002R',),
2829
('010101-0101',),
2930
('010101+0101',),
3031
('010101A0101',),
32+
('010190-900P',),
3133
])
3234
def test_returns_true_on_valid_ssn(value):
3335
assert fi_ssn(value)
@@ -36,10 +38,22 @@ def test_returns_true_on_valid_ssn(value):
3638
@pytest.mark.parametrize(('value',), [
3739
(None,),
3840
('',),
41+
('010190-001P',), # Too low serial
42+
('010190-000N',), # Too low serial
43+
('000190-0023',), # Invalid day
44+
('010090-002X',), # Invalid month
45+
('010190-002r',), # Invalid checksum
3946
('101010-0102',),
4047
('10a010-0101',),
4148
('101010-0\xe401',),
4249
('101010b0101',)
4350
])
4451
def test_returns_failed_validation_on_invalid_ssn(value):
4552
assert isinstance(fi_ssn(value), ValidationFailure)
53+
54+
55+
def test_returns_failed_validation_on_temporal_ssn_when_not_allowed():
56+
assert isinstance(
57+
fi_ssn('010190-900P', allow_temporal_ssn=False),
58+
ValidationFailure
59+
)

validators/i18n/fi.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
ssn_checkmarks = '0123456789ABCDEFHJKLMNPRSTUVWXY'
77
ssn_pattern = re.compile(
88
r"""^
9-
(?P<date>([0-2]\d|3[01])
10-
(0\d|1[012])
9+
(?P<date>(0[1-9]|[1-2]\d|3[01])
10+
(0[1-9]|1[012])
1111
(\d{{2}}))
1212
[A+-]
1313
(?P<serial>(\d{{3}}))
1414
(?P<checksum>[{checkmarks}])$""".format(checkmarks=ssn_checkmarks),
15-
re.VERBOSE | re.IGNORECASE
15+
re.VERBOSE
1616
)
1717

1818

@@ -52,7 +52,7 @@ def fi_business_id(business_id):
5252

5353

5454
@validator
55-
def fi_ssn(ssn):
55+
def fi_ssn(ssn, allow_temporal_ssn=True):
5656
"""
5757
Validate a Finnish Social Security Number.
5858
@@ -67,11 +67,16 @@ def fi_ssn(ssn):
6767
True
6868
6969
>>> fi_ssn('101010-0102')
70-
ValidationFailure(func=fi_ssn, args={'ssn': '101010-0102'})
70+
ValidationFailure(func=fi_ssn, args=...)
7171
7272
.. versionadded:: 0.5
7373
7474
:param ssn: Social Security Number to validate
75+
:param allow_temporal_ssn:
76+
Whether to accept temporal SSN numbers. Temporal SSN numbers are the
77+
ones where the serial is in the range [900-999]. By default temporal
78+
SSN numbers are valid.
79+
7580
"""
7681
if not ssn:
7782
return False
@@ -82,6 +87,8 @@ def fi_ssn(ssn):
8287
gd = result.groupdict()
8388
checksum = int(gd['date'] + gd['serial'])
8489
return (
90+
int(gd['serial']) >= 2 and
91+
(allow_temporal_ssn or int(gd['serial']) <= 899) and
8592
ssn_checkmarks[checksum % len(ssn_checkmarks)] ==
86-
gd['checksum'].upper()
93+
gd['checksum']
8794
)

0 commit comments

Comments
 (0)