From a80a441ab1fdfb93f24f4945e3335095b052733e Mon Sep 17 00:00:00 2001 From: Mehdi Samsami Date: Sat, 6 Jul 2024 12:14:26 +0330 Subject: [PATCH] add validators for base16 and base32 encodings --- CHANGES.md | 19 +++++++++++ SECURITY.md | 2 +- docs/api/encoding.md | 2 ++ docs/api/encoding.rst | 2 ++ src/validators/__init__.py | 6 ++-- src/validators/encoding.py | 42 ++++++++++++++++++++++++ tests/test_encoding.py | 66 +++++++++++++++++++++++++++++++++++++- 7 files changed, 135 insertions(+), 4 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index e0a3d97a..e1e71800 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,25 @@ Note to self: Breaking changes must increment either --> +## 0.31.0 (2024-07-08) + +_**Breaking**_ + +> No breaking changes were introduced in this version. + +_**Features**_ + +- feat: add validator for base16 encoding by @msamsami in [#386](https://github.com/python-validators/validators/pull/386) +- feat: add validator for base32 encoding by @msamsami in [#386](https://github.com/python-validators/validators/pull/386) + +_**Maintenance**_ + +- maint: bump version by @msamsami in [#386](https://github.com/python-validators/validators/pull/386) + +**Full Changelog**: [`0.29.0...0.30.0`](https://github.com/python-validators/validators/compare/0.30.0...0.31.0) + +--- + ## 0.30.0 (2024-07-04) _**Breaking**_ diff --git a/SECURITY.md b/SECURITY.md index 2231e167..dbf9c090 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,7 +4,7 @@ | Version | Supported | | ---------- | ------------------ | -| `>=0.30.0` | :white_check_mark: | +| `>=0.31.0` | :white_check_mark: | ## Reporting a Vulnerability diff --git a/docs/api/encoding.md b/docs/api/encoding.md index 8f2794cb..39c24ec4 100644 --- a/docs/api/encoding.md +++ b/docs/api/encoding.md @@ -1,4 +1,6 @@ # encoding +::: validators.encoding.base16 +::: validators.encoding.base32 ::: validators.encoding.base58 ::: validators.encoding.base64 diff --git a/docs/api/encoding.rst b/docs/api/encoding.rst index 55d1799a..2554c933 100644 --- a/docs/api/encoding.rst +++ b/docs/api/encoding.rst @@ -2,5 +2,7 @@ encoding -------- .. module:: validators.encoding +.. autofunction:: base16 +.. autofunction:: base32 .. autofunction:: base58 .. autofunction:: base64 diff --git a/src/validators/__init__.py b/src/validators/__init__.py index a58a574c..cf11e3a7 100644 --- a/src/validators/__init__.py +++ b/src/validators/__init__.py @@ -8,7 +8,7 @@ from .crypto_addresses import btc_address, eth_address, trx_address from .domain import domain from .email import email -from .encoding import base58, base64 +from .encoding import base16, base32, base58, base64 from .finance import cusip, isin, sedol from .hashes import md5, sha1, sha224, sha256, sha512 from .hostname import hostname @@ -60,6 +60,8 @@ # ... "email", # encodings + "base16", + "base32", "base58", "base64", # finance @@ -105,4 +107,4 @@ "validator", ) -__version__ = "0.30.0" +__version__ = "0.31.0" diff --git a/src/validators/encoding.py b/src/validators/encoding.py index f2720748..71efc849 100644 --- a/src/validators/encoding.py +++ b/src/validators/encoding.py @@ -7,6 +7,48 @@ from .utils import validator +@validator +def base16(value: str, /): + """Return whether or not given value is a valid base16 encoding. + + Examples: + >>> base16('a3f4b2') + # Output: True + >>> base16('a3f4Z1') + # Output: ValidationError(func=base16, args={'value': 'a3f4Z1'}) + + Args: + value: + base16 string to validate. + + Returns: + (Literal[True]): If `value` is a valid base16 encoding. + (ValidationError): If `value` is an invalid base16 encoding. + """ + return re.match(r"^[0-9A-Fa-f]+$", value) if value else False + + +@validator +def base32(value: str, /): + """Return whether or not given value is a valid base32 encoding. + + Examples: + >>> base32('MFZWIZLTOQ======') + # Output: True + >>> base32('MfZW3zLT9Q======') + # Output: ValidationError(func=base32, args={'value': 'MfZW3zLT9Q======'}) + + Args: + value: + base32 string to validate. + + Returns: + (Literal[True]): If `value` is a valid base32 encoding. + (ValidationError): If `value` is an invalid base32 encoding. + """ + return re.match(r"^[A-Z2-7]+=*$", value) if value else False + + @validator def base58(value: str, /): """Return whether or not given value is a valid base58 encoding. diff --git a/tests/test_encoding.py b/tests/test_encoding.py index 86567ffb..db5bccf8 100644 --- a/tests/test_encoding.py +++ b/tests/test_encoding.py @@ -4,7 +4,71 @@ import pytest # local -from validators import ValidationError, base58, base64 +from validators import ValidationError, base16, base32, base58, base64 + +# ==> base16 <== # + + +@pytest.mark.parametrize( + "value", + [ + "a3f4b2", + "01ef", + "abcdef0123456789", + "1234567890abcdef", + "1a2b3c", + "abcdef", + "000102030405060708090A0B0C0D0E0F", + ], +) +def test_returns_true_on_valid_base16(value: str): + """Test returns true on valid base16.""" + assert base16(value) + + +@pytest.mark.parametrize( + "value", + ["12345g", "hello world", "1234567890abcdeg", "GHIJKL", "12345G", "!@#$%^", "1a2h3c", "a3f4Z1"], +) +def test_returns_failed_validation_on_invalid_base16(value: str): + """Test returns failed validation on invalid base16.""" + assert isinstance(base16(value), ValidationError) + + +# ==> base32 <== # + + +@pytest.mark.parametrize( + "value", + [ + "JBSWY3DPEHPK3PXP", + "MFRGGZDFMZTWQ2LK", + "MZXW6YTBOI======", + "MFZWIZLTOQ======", + "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ", + "MFRGGZDFMZTWQ2LKNNWG23Q=", + ], +) +def test_returns_true_on_valid_base32(value: str): + """Test returns true on valid base32.""" + assert base32(value) + + +@pytest.mark.parametrize( + "value", + [ + "ThisIsNotBase32!", + "12345!", + "Any==invalid=base32=", + "MzXW6yTBOI======", + "JBSWY8DPEHPK9PXP", + "MfZW3zLT9Q======", + ], +) +def test_returns_failed_validation_on_invalid_base32(value: str): + """Test returns failed validation on invalid base32.""" + assert isinstance(base32(value), ValidationError) + # ==> base58 <== #