From 6666c1ec6c71d0f22947f537ac6892e0ef6ce843 Mon Sep 17 00:00:00 2001 From: Jovial Joe Jayarson Date: Mon, 6 Mar 2023 12:11:24 +0530 Subject: [PATCH] maint: improve `hashes` and `iban` modules - re-formats `hashes` and `iban.py`, fix typos - Uses type hints, adds relevant doc refs - Updates corresponding tests --- docs/index.md | 4 ++ tests/test_domain.py | 2 +- tests/test_email.py | 2 +- tests/test_hashes.py | 156 +++++++++++++++++++++++++++++++++++++++++ tests/test_iban.py | 27 ++++---- tests/test_md5.py | 22 ------ tests/test_sha1.py | 22 ------ tests/test_sha224.py | 22 ------ tests/test_sha256.py | 22 ------ tests/test_sha512.py | 37 ---------- validators/hashes.py | 160 +++++++++++++++++++++++-------------------- validators/iban.py | 60 +++++++--------- 12 files changed, 288 insertions(+), 248 deletions(-) create mode 100644 tests/test_hashes.py delete mode 100644 tests/test_md5.py delete mode 100644 tests/test_sha1.py delete mode 100644 tests/test_sha224.py delete mode 100644 tests/test_sha256.py delete mode 100644 tests/test_sha512.py diff --git a/docs/index.md b/docs/index.md index 4624f9f8..5b0dbd44 100644 --- a/docs/index.md +++ b/docs/index.md @@ -12,4 +12,8 @@ ::: validators.email +::: validators.hashes + +::: validators.iban + ::: validators.length diff --git a/tests/test_domain.py b/tests/test_domain.py index b619a329..bfea791d 100644 --- a/tests/test_domain.py +++ b/tests/test_domain.py @@ -1,7 +1,7 @@ """Test Domain.""" # -*- coding: utf-8 -*- -# standard +# external import pytest # local diff --git a/tests/test_email.py b/tests/test_email.py index 6d980bc6..1166bf4b 100644 --- a/tests/test_email.py +++ b/tests/test_email.py @@ -1,7 +1,7 @@ """Test eMail.""" # -*- coding: utf-8 -*- -# standard +# external import pytest # local diff --git a/tests/test_hashes.py b/tests/test_hashes.py new file mode 100644 index 00000000..b1c28178 --- /dev/null +++ b/tests/test_hashes.py @@ -0,0 +1,156 @@ +"""Test Hashes.""" +# -*- coding: utf-8 -*- + +# external +import pytest + +# local +from validators import md5, sha1, sha224, sha256, sha512, ValidationFailure + + +# ==> md5 <== # + + +@pytest.mark.parametrize( + "value", ["d41d8cd98f00b204e9800998ecf8427e", "D41D8CD98F00B204E9800998ECF8427E"] +) +def test_returns_true_on_valid_md5(value: str): + """Test returns true on valid md5.""" + assert md5(value) + + +@pytest.mark.parametrize( + "value", + [ + "z41d8cd98f00b204e9800998ecf8427e", + "z8cd98f00b204e9800998ecf8427e", + "z4aaaa1d8cd98f00b204e9800998ecf8427e", + ], +) +def test_returns_failed_validation_on_invalid_md5(value: str): + """Test returns failed validation on invalid md5.""" + assert isinstance(md5(value), ValidationFailure) + + +# ==> sha1 <== # + + +@pytest.mark.parametrize( + "value", + ["da39a3ee5e6b4b0d3255bfef95601890afd80709", "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"], +) +def test_returns_true_on_valid_sha1(value: str): + """Test returns true on valid sha1.""" + assert sha1(value) + + +@pytest.mark.parametrize( + "value", + [ + "za39a3ee5e6b4b0d3255bfef95601890afd80709", + "da39e5e6b4b0d3255bfef95601890afd80709", + "daaaa39a3ee5e6b4b0d3255bfef95601890afd80709", + ], +) +def test_returns_failed_validation_on_invalid_sha1(value: str): + """Test returns failed validation on invalid sha1.""" + assert isinstance(sha1(value), ValidationFailure) + + +# ==> sha224 <== # + + +@pytest.mark.parametrize( + "value", + [ + "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", + "D14A028C2A3A2BC9476102BB288234C415A2B01F828EA62AC5B3E42F", + ], +) +def test_returns_true_on_valid_sha224(value: str): + """Test returns true on valid sha224.""" + assert sha224(value) + + +@pytest.mark.parametrize( + "value", + [ + "z14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", + "d028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", + "daaa14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", + ], +) +def test_returns_failed_validation_on_invalid_sha224(value: str): + """Test returns failed validation on invalid sha224.""" + assert isinstance(sha224(value), ValidationFailure) + + +# ==> sha256 <== # + + +@pytest.mark.parametrize( + "value", + [ + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + ], +) +def test_returns_true_on_valid_sha256(value: str): + """Test returns true on valid sha256.""" + assert sha256(value) + + +@pytest.mark.parametrize( + "value", + [ + "z3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ec44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "eaaaa3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + ], +) +def test_returns_failed_validation_on_invalid_sha256(value: str): + """Test returns failed validation on invalid sha256.""" + assert isinstance(sha256(value), ValidationFailure) + + +# ==> sha256 <== # + + +@pytest.mark.parametrize( + "value", + [ + ( + "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d" + "13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" + ), + ( + "CF83E1357EEFB8BDF1542850D66D8007D620E4050B5715DC83F4A921D36CE9CE47D0D" + "13C5D85F2B0FF8318D2877EEC2F63B931BD47417A81A538327AF927DA3E" + ), + ], +) +def test_returns_true_on_valid_sha512(value: str): + """Test returns true on valid sha512.""" + assert sha512(value) + + +@pytest.mark.parametrize( + "value", + [ + ( + "zf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d" + "13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" + ), + ( + "cf8357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c" + "5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" + ), + ( + "cf8aaaa3e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce4" + "7d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" + ), + ], +) +def test_returns_failed_validation_on_invalid_sha512(value: str): + """Test returns failed validation on invalid sha512.""" + assert isinstance(sha512(value), ValidationFailure) diff --git a/tests/test_iban.py b/tests/test_iban.py index 2dcca652..f76c8e3b 100644 --- a/tests/test_iban.py +++ b/tests/test_iban.py @@ -1,21 +1,20 @@ +"""Test IBAN.""" # -*- coding: utf-8 -*- + +# external import pytest -import validators +# local +from validators import iban, ValidationFailure -@pytest.mark.parametrize('value', [ - 'GB82WEST12345698765432', - 'NO9386011117947' -]) -def test_returns_true_on_valid_iban(value): - assert validators.iban(value) +@pytest.mark.parametrize("value", ["GB82WEST12345698765432", "NO9386011117947"]) +def test_returns_true_on_valid_iban(value: str): + """Test returns true on valid iban.""" + assert iban(value) -@pytest.mark.parametrize('value', [ - 'GB81WEST12345698765432', - 'NO9186011117947' -]) -def test_returns_failed_validation_on_invalid_iban(value): - result = validators.iban(value) - assert isinstance(result, validators.ValidationFailure) +@pytest.mark.parametrize("value", ["GB81WEST12345698765432", "NO9186011117947"]) +def test_returns_failed_validation_on_invalid_iban(value: str): + """Test returns failed validation on invalid iban.""" + assert isinstance(iban(value), ValidationFailure) diff --git a/tests/test_md5.py b/tests/test_md5.py deleted file mode 100644 index 3efb1d69..00000000 --- a/tests/test_md5.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -import pytest - -import validators - - -@pytest.mark.parametrize('value', [ - 'd41d8cd98f00b204e9800998ecf8427e', - 'D41D8CD98F00B204E9800998ECF8427E' -]) -def test_returns_true_on_valid_md5(value): - assert validators.md5(value) - - -@pytest.mark.parametrize('value', [ - 'z41d8cd98f00b204e9800998ecf8427e', - 'z8cd98f00b204e9800998ecf8427e', - 'z4aaaa1d8cd98f00b204e9800998ecf8427e' -]) -def test_returns_failed_validation_on_invalid_md5(value): - result = validators.md5(value) - assert isinstance(result, validators.ValidationFailure) diff --git a/tests/test_sha1.py b/tests/test_sha1.py deleted file mode 100644 index b729009a..00000000 --- a/tests/test_sha1.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -import pytest - -import validators - - -@pytest.mark.parametrize('value', [ - 'da39a3ee5e6b4b0d3255bfef95601890afd80709', - 'DA39A3EE5E6B4B0D3255BFEF95601890AFD80709' -]) -def test_returns_true_on_valid_sha1(value): - assert validators.sha1(value) - - -@pytest.mark.parametrize('value', [ - 'za39a3ee5e6b4b0d3255bfef95601890afd80709', - 'da39e5e6b4b0d3255bfef95601890afd80709', - 'daaaa39a3ee5e6b4b0d3255bfef95601890afd80709' -]) -def test_returns_failed_validation_on_invalid_sha1(value): - result = validators.sha1(value) - assert isinstance(result, validators.ValidationFailure) diff --git a/tests/test_sha224.py b/tests/test_sha224.py deleted file mode 100644 index 225275b9..00000000 --- a/tests/test_sha224.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -import pytest - -import validators - - -@pytest.mark.parametrize('value', [ - 'd14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f', - 'D14A028C2A3A2BC9476102BB288234C415A2B01F828EA62AC5B3E42F' -]) -def test_returns_true_on_valid_sha224(value): - assert validators.sha224(value) - - -@pytest.mark.parametrize('value', [ - 'z14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f', - 'd028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f', - 'daaa14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f' -]) -def test_returns_failed_validation_on_invalid_sha224(value): - result = validators.sha224(value) - assert isinstance(result, validators.ValidationFailure) diff --git a/tests/test_sha256.py b/tests/test_sha256.py deleted file mode 100644 index b9c20776..00000000 --- a/tests/test_sha256.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -import pytest - -import validators - - -@pytest.mark.parametrize('value', [ - 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', - 'E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855' -]) -def test_returns_true_on_valid_sha256(value): - assert validators.sha256(value) - - -@pytest.mark.parametrize('value', [ - 'z3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', - 'ec44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', - 'eaaaa3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', -]) -def test_returns_failed_validation_on_invalid_sha256(value): - result = validators.sha256(value) - assert isinstance(result, validators.ValidationFailure) diff --git a/tests/test_sha512.py b/tests/test_sha512.py deleted file mode 100644 index 7a7aabba..00000000 --- a/tests/test_sha512.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding: utf-8 -*- -import pytest - -import validators - - -@pytest.mark.parametrize('value', [ - ( - 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d' - '13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e' - ), - ( - 'CF83E1357EEFB8BDF1542850D66D8007D620E4050B5715DC83F4A921D36CE9CE47D0D' - '13C5D85F2B0FF8318D2877EEC2F63B931BD47417A81A538327AF927DA3E' - ) -]) -def test_returns_true_on_valid_sha512(value): - assert validators.sha512(value) - - -@pytest.mark.parametrize('value', [ - ( - 'zf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d' - '13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e' - ), - ( - 'cf8357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c' - '5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e' - ), - ( - 'cf8aaaa3e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce4' - '7d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e' - ) -]) -def test_returns_failed_validation_on_invalid_sha512(value): - result = validators.sha512(value) - assert isinstance(result, validators.ValidationFailure) diff --git a/validators/hashes.py b/validators/hashes.py index 4db7f78e..a3736df0 100644 --- a/validators/hashes.py +++ b/validators/hashes.py @@ -1,121 +1,135 @@ +"""Hashes.""" +# -*- coding: utf-8 -*- + +# standard import re +# local from .utils import validator -md5_regex = re.compile( - r"^[0-9a-f]{32}$", - re.IGNORECASE -) -sha1_regex = re.compile( - r"^[0-9a-f]{40}$", - re.IGNORECASE -) -sha224_regex = re.compile( - r"^[0-9a-f]{56}$", - re.IGNORECASE -) -sha256_regex = re.compile( - r"^[0-9a-f]{64}$", - re.IGNORECASE -) -sha512_regex = re.compile( - r"^[0-9a-f]{128}$", - re.IGNORECASE -) - @validator -def md5(value): - """ - Return whether or not given value is a valid MD5 hash. - - Examples:: +def md5(value: str): + """Return whether or not given value is a valid MD5 hash. + Examples: >>> md5('d41d8cd98f00b204e9800998ecf8427e') - True - + # Output: True >>> md5('900zz11') - ValidationFailure(func=md5, args={'value': '900zz11'}) + # Output: ValidationFailure(func=md5, args={'value': '900zz11'}) - :param value: MD5 string to validate - """ - return md5_regex.match(value) + Args: + value: MD5 string to validate. + Returns: + (Literal[True]): + If `value` is a valid MD5 hash. + (ValidationFailure): + If `value` is an invalid MD5 hash. -@validator -def sha1(value): + > *New in version 0.12.1* """ - Return whether or not given value is a valid SHA1 hash. + return re.match(r"^[0-9a-f]{32}$", value, re.IGNORECASE) - Examples:: - >>> sha1('da39a3ee5e6b4b0d3255bfef95601890afd80709') - True +@validator +def sha1(value: str): + """Return whether or not given value is a valid SHA1 hash. + Examples: + >>> sha1('da39a3ee5e6b4b0d3255bfef95601890afd80709') + # Output: True >>> sha1('900zz11') - ValidationFailure(func=sha1, args={'value': '900zz11'}) + # Output: ValidationFailure(func=sha1, args={'value': '900zz11'}) - :param value: SHA1 string to validate - """ - return sha1_regex.match(value) + Args: + value: SHA1 string to validate. + Returns: + (Literal[True]): + If `value` is a valid SHA1 hash. + (ValidationFailure): + If `value` is an invalid SHA1 hash. -@validator -def sha224(value): + > *New in version 0.12.1* """ - Return whether or not given value is a valid SHA224 hash. + return re.match(r"^[0-9a-f]{40}$", value, re.IGNORECASE) - Examples:: - >>> sha224('d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f') - True +@validator +def sha224(value: str): + """Return whether or not given value is a valid SHA224 hash. + Examples: + >>> sha224('d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f') + # Output: True >>> sha224('900zz11') - ValidationFailure(func=sha224, args={'value': '900zz11'}) + # Output: ValidationFailure(func=sha224, args={'value': '900zz11'}) - :param value: SHA224 string to validate - """ - return sha224_regex.match(value) + Args: + value: SHA224 string to validate. + Returns: + (Literal[True]): + If `value` is a valid SHA224 hash. + (ValidationFailure): + If `value` is an invalid SHA224 hash. -@validator -def sha256(value): + > *New in version 0.12.1* """ - Return whether or not given value is a valid SHA256 hash. + return re.match(r"^[0-9a-f]{56}$", value, re.IGNORECASE) - Examples:: +@validator +def sha256(value: str): + """Return whether or not given value is a valid SHA256 hash. + + Examples: >>> sha256( - ... 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b' - ... '855' + ... 'e3b0c44298fc1c149afbf4c8996fb924' + ... '27ae41e4649b934ca495991b7852b855' ... ) - True - + # Output: True >>> sha256('900zz11') - ValidationFailure(func=sha256, args={'value': '900zz11'}) + # Output: ValidationFailure(func=sha256, args={'value': '900zz11'}) - :param value: SHA256 string to validate - """ - return sha256_regex.match(value) + Args: + value: SHA256 string to validate. + Returns: + (Literal[True]): + If `value` is a valid SHA256 hash. + (ValidationFailure): + If `value` is an invalid SHA256 hash. -@validator -def sha512(value): + > *New in version 0.12.1* """ - Return whether or not given value is a valid SHA512 hash. + return re.match(r"^[0-9a-f]{64}$", value, re.IGNORECASE) + - Examples:: +@validator +def sha512(value: str): + """Return whether or not given value is a valid SHA512 hash. + Examples: >>> sha512( ... 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce' ... '9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af9' ... '27da3e' ... ) - True - + # Output: True >>> sha512('900zz11') - ValidationFailure(func=sha512, args={'value': '900zz11'}) + # Output: ValidationFailure(func=sha512, args={'value': '900zz11'}) + + Args: + value: SHA512 string to validate. + + Returns: + (Literal[True]): + If `value` is a valid SHA512 hash. + (ValidationFailure): + If `value` is an invalid SHA512 hash. - :param value: SHA512 string to validate + > *New in version 0.12.1* """ - return sha512_regex.match(value) + return re.match(r"^[0-9a-f]{128}$", value, re.IGNORECASE) diff --git a/validators/iban.py b/validators/iban.py index 7413d127..bf44562f 100644 --- a/validators/iban.py +++ b/validators/iban.py @@ -1,52 +1,44 @@ +"""IBAN.""" +# -*- coding: utf-8 -*- + +# standard import re +# local from .utils import validator -regex = ( - r'^[A-Z]{2}[0-9]{2}[A-Z0-9]{11,30}$' -) -pattern = re.compile(regex) - -def char_value(char): - """A=10, B=11, ..., Z=35 - """ - if char.isdigit(): - return int(char) - else: - return 10 + ord(char) - ord('A') +def _char_value(char: str): + """A=10, B=11, ..., Z=35.""" + return char if char.isdigit() else str(10 + ord(char) - ord("A")) -def modcheck(value): - """Check if the value string passes the mod97-test. - """ +def _mod_check(value: str): + """Check if the value string passes the mod97-test.""" # move country code and check numbers to end rearranged = value[4:] + value[:4] - # convert letters to numbers - converted = [char_value(char) for char in rearranged] - # interpret as integer - integerized = int(''.join([str(i) for i in converted])) - return (integerized % 97 == 1) + return int("".join(_char_value(char) for char in rearranged)) % 97 == 1 @validator -def iban(value): - """ - Return whether or not given value is a valid IBAN code. - - If the value is a valid IBAN this function returns ``True``, otherwise - :class:`~validators.utils.ValidationFailure`. - - Examples:: +def iban(value: str): + """Return whether or not given value is a valid IBAN code. + Examples: >>> iban('DE29100500001061045672') - True - + # Output: True >>> iban('123456') - ValidationFailure(func=iban, ...) + # Output: ValidationFailure(func=iban, ...) + + Args: + value: IBAN string to validate. - .. versionadded:: 0.8 + Returns: + (Literal[True]): + If `value` is a valid IBAN code. + (ValidationFailure): + If `value` is an invalid IBAN code. - :param value: IBAN string to validate + > *New in version 0.8.0* """ - return pattern.match(value) and modcheck(value) + return re.match(r"^[A-Z]{2}[0-9]{2}[A-Z0-9]{11,30}$", value) and _mod_check(value)