Skip to content

Commit e5d7b4a

Browse files
msamsamiyozachar
andauthored
feat: add validators for base16 and base32 encodings (#386)
- add validators for `base16` and `base32` encodings - fix: typos in `CHANGES.md` --------- Co-authored-by: Yozachar <[email protected]>
1 parent 860ca46 commit e5d7b4a

File tree

7 files changed

+134
-4
lines changed

7 files changed

+134
-4
lines changed

CHANGES.md

+18
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,24 @@ Note to self: Breaking changes must increment either
99
1010
-->
1111

12+
## 0.31.0 (2024-07-08)
13+
14+
_**Breaking**_
15+
16+
> No breaking changes were introduced in this version.
17+
18+
_**Features**_
19+
20+
- feat: add validators for `base16` and `base32` encodings by @msamsami in [#386](https://github.com/python-validators/validators/pull/386)
21+
22+
_**Maintenance**_
23+
24+
- maint: bump version by @msamsami in [#386](https://github.com/python-validators/validators/pull/386)
25+
26+
**Full Changelog**: [`0.30.0...0.31.0`](https://github.com/python-validators/validators/compare/0.30.0...0.31.0)
27+
28+
---
29+
1230
## 0.30.0 (2024-07-04)
1331

1432
_**Breaking**_

SECURITY.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
| Version | Supported |
66
| ---------- | ------------------ |
7-
| `>=0.30.0` | :white_check_mark: |
7+
| `>=0.31.0` | :white_check_mark: |
88

99
## Reporting a Vulnerability
1010

docs/api/encoding.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# encoding
22

3+
::: validators.encoding.base16
4+
::: validators.encoding.base32
35
::: validators.encoding.base58
46
::: validators.encoding.base64

docs/api/encoding.rst

+2
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,7 @@ encoding
22
--------
33

44
.. module:: validators.encoding
5+
.. autofunction:: base16
6+
.. autofunction:: base32
57
.. autofunction:: base58
68
.. autofunction:: base64

src/validators/__init__.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from .crypto_addresses import btc_address, eth_address, trx_address
99
from .domain import domain
1010
from .email import email
11-
from .encoding import base58, base64
11+
from .encoding import base16, base32, base58, base64
1212
from .finance import cusip, isin, sedol
1313
from .hashes import md5, sha1, sha224, sha256, sha512
1414
from .hostname import hostname
@@ -60,6 +60,8 @@
6060
# ...
6161
"email",
6262
# encodings
63+
"base16",
64+
"base32",
6365
"base58",
6466
"base64",
6567
# finance
@@ -105,4 +107,4 @@
105107
"validator",
106108
)
107109

108-
__version__ = "0.30.0"
110+
__version__ = "0.31.0"

src/validators/encoding.py

+42
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,48 @@
77
from .utils import validator
88

99

10+
@validator
11+
def base16(value: str, /):
12+
"""Return whether or not given value is a valid base16 encoding.
13+
14+
Examples:
15+
>>> base16('a3f4b2')
16+
# Output: True
17+
>>> base16('a3f4Z1')
18+
# Output: ValidationError(func=base16, args={'value': 'a3f4Z1'})
19+
20+
Args:
21+
value:
22+
base16 string to validate.
23+
24+
Returns:
25+
(Literal[True]): If `value` is a valid base16 encoding.
26+
(ValidationError): If `value` is an invalid base16 encoding.
27+
"""
28+
return re.match(r"^[0-9A-Fa-f]+$", value) if value else False
29+
30+
31+
@validator
32+
def base32(value: str, /):
33+
"""Return whether or not given value is a valid base32 encoding.
34+
35+
Examples:
36+
>>> base32('MFZWIZLTOQ======')
37+
# Output: True
38+
>>> base32('MfZW3zLT9Q======')
39+
# Output: ValidationError(func=base32, args={'value': 'MfZW3zLT9Q======'})
40+
41+
Args:
42+
value:
43+
base32 string to validate.
44+
45+
Returns:
46+
(Literal[True]): If `value` is a valid base32 encoding.
47+
(ValidationError): If `value` is an invalid base32 encoding.
48+
"""
49+
return re.match(r"^[A-Z2-7]+=*$", value) if value else False
50+
51+
1052
@validator
1153
def base58(value: str, /):
1254
"""Return whether or not given value is a valid base58 encoding.

tests/test_encoding.py

+65-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,71 @@
44
import pytest
55

66
# local
7-
from validators import ValidationError, base58, base64
7+
from validators import ValidationError, base16, base32, base58, base64
8+
9+
# ==> base16 <== #
10+
11+
12+
@pytest.mark.parametrize(
13+
"value",
14+
[
15+
"a3f4b2",
16+
"01ef",
17+
"abcdef0123456789",
18+
"1234567890abcdef",
19+
"1a2b3c",
20+
"abcdef",
21+
"000102030405060708090A0B0C0D0E0F",
22+
],
23+
)
24+
def test_returns_true_on_valid_base16(value: str):
25+
"""Test returns true on valid base16."""
26+
assert base16(value)
27+
28+
29+
@pytest.mark.parametrize(
30+
"value",
31+
["12345g", "hello world", "1234567890abcdeg", "GHIJKL", "12345G", "!@#$%^", "1a2h3c", "a3f4Z1"],
32+
)
33+
def test_returns_failed_validation_on_invalid_base16(value: str):
34+
"""Test returns failed validation on invalid base16."""
35+
assert isinstance(base16(value), ValidationError)
36+
37+
38+
# ==> base32 <== #
39+
40+
41+
@pytest.mark.parametrize(
42+
"value",
43+
[
44+
"JBSWY3DPEHPK3PXP",
45+
"MFRGGZDFMZTWQ2LK",
46+
"MZXW6YTBOI======",
47+
"MFZWIZLTOQ======",
48+
"GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ",
49+
"MFRGGZDFMZTWQ2LKNNWG23Q=",
50+
],
51+
)
52+
def test_returns_true_on_valid_base32(value: str):
53+
"""Test returns true on valid base32."""
54+
assert base32(value)
55+
56+
57+
@pytest.mark.parametrize(
58+
"value",
59+
[
60+
"ThisIsNotBase32!",
61+
"12345!",
62+
"Any==invalid=base32=",
63+
"MzXW6yTBOI======",
64+
"JBSWY8DPEHPK9PXP",
65+
"MfZW3zLT9Q======",
66+
],
67+
)
68+
def test_returns_failed_validation_on_invalid_base32(value: str):
69+
"""Test returns failed validation on invalid base32."""
70+
assert isinstance(base32(value), ValidationError)
71+
872

973
# ==> base58 <== #
1074

0 commit comments

Comments
 (0)