Skip to content

Commit ed98a6a

Browse files
Clean up mac_address.py validation logic
1 parent c8a419e commit ed98a6a

File tree

1 file changed

+36
-28
lines changed

1 file changed

+36
-28
lines changed

pydantic_extra_types/mac_address.py

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
from pydantic import GetCoreSchemaHandler
1010
from pydantic_core import PydanticCustomError, core_schema
1111

12+
MINIMUM_LENGTH: int = 14
13+
ALLOWED_CHUNK_COUNTS: tuple[int, int, int] = (6, 8, 20)
14+
1215

1316
class MacAddress(str):
1417
"""Represents a MAC address and provides methods for conversion, validation, and serialization.
@@ -63,36 +66,41 @@ def _validate(cls, __input_value: str, _: Any) -> str:
6366
@staticmethod
6467
def validate_mac_address(value: bytes) -> str:
6568
"""Validate a MAC Address from the provided byte value."""
66-
string = value.decode()
67-
if len(string) < 14:
69+
raw = value.decode()
70+
if len(raw) < MINIMUM_LENGTH:
6871
raise PydanticCustomError(
6972
'mac_address_len',
7073
'Length for a {mac_address} MAC address must be {required_length}',
71-
{'mac_address': string, 'required_length': 14},
74+
{'mac_address': raw, 'required_length': MINIMUM_LENGTH},
7275
)
73-
for sep, partbytes in ((':', 2), ('-', 2), ('.', 4)):
74-
if sep in string:
75-
parts = string.split(sep)
76-
if any(len(part) != partbytes for part in parts):
77-
raise PydanticCustomError(
78-
'mac_address_format',
79-
f'Must have the format xx{sep}xx{sep}xx{sep}xx{sep}xx{sep}xx',
80-
)
81-
if len(parts) * partbytes // 2 not in (6, 8, 20):
82-
raise PydanticCustomError(
83-
'mac_address_format',
84-
'Length for a {mac_address} MAC address must be {required_length}',
85-
{'mac_address': string, 'required_length': (6, 8, 20)},
86-
)
87-
mac_address = []
76+
77+
for seperator, chunk_len in ((':', 2), ('-', 2), ('.', 4)):
78+
if seperator not in raw:
79+
continue
80+
81+
parts = raw.split(seperator)
82+
if any(len(p) != chunk_len for p in parts):
83+
raise PydanticCustomError(
84+
'mac_address_format',
85+
f'Must have the format xx{seperator}xx{seperator}xx{seperator}xx{seperator}xx{seperator}xx',
86+
)
87+
88+
total_bytes = (len(parts) * chunk_len) // 2
89+
if total_bytes not in ALLOWED_CHUNK_COUNTS:
90+
raise PydanticCustomError(
91+
'mac_address_format',
92+
'Length for a {mac_address} MAC address must be {required_length}',
93+
{'mac_address': raw, 'required_length': ALLOWED_CHUNK_COUNTS},
94+
)
95+
96+
try:
97+
mac_bytes: list[int] = []
8898
for part in parts:
89-
for idx in range(0, partbytes, 2):
90-
try:
91-
byte_value = int(part[idx : idx + 2], 16)
92-
except ValueError as exc:
93-
raise PydanticCustomError('mac_address_format', 'Unrecognized format') from exc
94-
else:
95-
mac_address.append(byte_value)
96-
return ':'.join(f'{b:02x}' for b in mac_address)
97-
else:
98-
raise PydanticCustomError('mac_address_format', 'Unrecognized format')
99+
for i in range(0, chunk_len, 2):
100+
mac_bytes.append(int(part[i:i + 2], base=16))
101+
except ValueError as exc:
102+
raise PydanticCustomError('mac_address_format', 'Unrecognized format') from exc
103+
104+
return ':'.join(f'{b:02x}' for b in mac_bytes)
105+
106+
raise PydanticCustomError('mac_address_format', 'Unrecognized format')

0 commit comments

Comments
 (0)