Skip to content

Commit a4f644e

Browse files
Merge pull request #15 from codonlibrary/nhsnumber-tweak
nhsNumberGenerator logic tweak.
2 parents 9ac22a7 + f698698 commit a4f644e

4 files changed

Lines changed: 124 additions & 70 deletions

File tree

codonPython/nhsNumber.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import random
2+
import numpy as np
3+
4+
5+
def nhsNumberValidator(number: int)->bool:
6+
"""
7+
Validate NHS Number according to modulus 11 checks as recorded in the data dictionary.
8+
https://www.datadictionary.nhs.uk/data_dictionary/attributes/n/nhs/nhs_number_de.asp?shownav=1
9+
10+
Parameters
11+
----------
12+
number : int
13+
10 digit integer to validate.
14+
15+
Returns
16+
----------
17+
bool
18+
If the number passes modulus 11 checks a.k.a. is valid.
19+
20+
Examples
21+
---------
22+
>>> nhsNumberValidator(8429141456)
23+
True
24+
>>> nhsNumberValidator(8429141457)
25+
False
26+
"""
27+
28+
if not isinstance(number, int):
29+
raise ValueError("Please input a positive 10 digit integer to validate.")
30+
if number < 0:
31+
raise ValueError("Please input a postitive 10 digit integer to validate.")
32+
digits = [int(digit) for digit in str(number)]
33+
# NHS Numbers are 10 digits long.
34+
if not len(digits) == 10:
35+
raise ValueError("Please input a postitive 10 digit integer to validate.")
36+
# Apply weighting to first 9 digits
37+
weighted_digits = np.dot(np.array(digits[:9]), np.arange(10,1,-1))
38+
# Validity is based on the check digit, which has to be equal to `remainder`
39+
remainder = weighted_digits % 11
40+
check_digit = 11 - remainder
41+
if check_digit == 11:
42+
check_digit = 0
43+
if check_digit == digits[-1]:
44+
return True
45+
else:
46+
return False
47+
48+
def nhsNumberGenerator(to_generate: int, random_state: int = None)->list:
49+
"""
50+
Generates up to 1M random NHS number(s) compliant with modulus 11 checks recorded
51+
in the data dictonary.
52+
https://www.datadictionary.nhs.uk/data_dictionary/attributes/n/nhs/nhs_number_de.asp?shownav=1
53+
54+
Parameters
55+
----------
56+
to_generate : int
57+
number of NHS numbers to generate
58+
random_state : int, default : None
59+
Optional seed for random number generation, for testing and reproducibility.
60+
61+
Returns
62+
----------
63+
generated : list
64+
List of randomly generated NHS numbers
65+
66+
Examples
67+
---------
68+
>>> nhsNumberGenerator(2, random_state=42)
69+
[8429141456, 2625792787]
70+
"""
71+
72+
if random_state:
73+
random.seed(random_state)
74+
if not isinstance(to_generate, int):
75+
raise ValueError("Please input a positive integer to generate numbers.")
76+
if to_generate > 1000000:
77+
raise ValueError("More than one million values requested")
78+
if to_generate < 0:
79+
raise ValueError("Please input a postitive integer to generate numbers.")
80+
81+
generated = []
82+
while len(generated) < to_generate:
83+
# Random 10 digit integer, starting with non-zero digit
84+
number = random.randint(1000000000, 9999999999)
85+
if nhsNumberValidator(number):
86+
generated.append(number)
87+
return generated

codonPython/nhsNumberGenerator.py

Lines changed: 0 additions & 49 deletions
This file was deleted.

codonPython/tests/nhsNumberGenerator_test.py

Lines changed: 0 additions & 21 deletions
This file was deleted.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from codonPython.nhsNumber import nhsNumberGenerator, nhsNumberValidator
2+
import numpy as np
3+
import pytest
4+
import random
5+
6+
7+
@pytest.mark.parametrize("to_generate, random_state, expected", [
8+
(3, 42, [8429141456, 2625792787, 8235363119]),
9+
(2, 1, [9598980006, 6597925149])
10+
])
11+
def test_nhsNumberGenerator_BAU(to_generate, random_state, expected):
12+
assert expected == nhsNumberGenerator(to_generate, random_state=random_state)
13+
14+
@pytest.mark.parametrize("to_generate", [
15+
4.2,
16+
1000001,
17+
-1
18+
])
19+
def test_nhsNumberGenerator_valueErrors(to_generate):
20+
with pytest.raises(ValueError):
21+
nhsNumberGenerator(to_generate)
22+
23+
@pytest.mark.parametrize("to_validate, expected", [
24+
(9598980006, True),
25+
(9598980007, False)
26+
])
27+
def test_nhsNumberValidator_BAU(to_validate, expected):
28+
assert expected == nhsNumberValidator(to_validate)
29+
30+
@pytest.mark.parametrize("to_validate", [
31+
4.2,
32+
1000001,
33+
-1
34+
])
35+
def test_nhsNumberValidator_valueErrors(to_validate):
36+
with pytest.raises(ValueError):
37+
nhsNumberValidator(to_validate)

0 commit comments

Comments
 (0)