Better passport validation

This commit is contained in:
Dan Buch 2021-01-10 12:39:50 -05:00
parent 03afc5a28b
commit ffc3934487
Signed by: meatballhat
GPG Key ID: 9685130D8B763EA7

View File

@ -10,6 +10,8 @@ def main() -> int:
NoneString = typing.Optional[str]
VALID_EYE_COLORS = ("amb", "blu", "brn", "gry", "grn", "hzl", "oth")
class Passport:
byr: NoneString = None
@ -22,13 +24,68 @@ class Passport:
pid: NoneString = None
def is_valid(self) -> bool:
return all(
[
getattr(self, attr) is not None
for attr in ("byr", "ecl", "eyr", "hcl", "hgt", "iyr", "pid")
]
return (
self._is_year_in_range(self.byr, range(1920, 2003))
and self._is_year_in_range(self.iyr, range(2010, 2021))
and self._is_year_in_range(self.eyr, range(2020, 2031))
and self._has_valid_height()
and self._has_valid_hair_color()
and self.ecl in VALID_EYE_COLORS
and self._has_valid_passport_id()
)
def _has_valid_height(self) -> bool:
if self.hgt is None:
return False
height_value = 0
height_value_string = self.hgt.replace("cm", "").replace("in", "")
if not height_value_string.isdigit():
return False
height = int(height_value_string)
if self.hgt.endswith("cm") and height in range(150, 194):
return True
elif self.hgt.endswith("in") and height in range(59, 77):
return True
return False
def _has_valid_hair_color(self) -> bool:
if self.hcl is None:
return False
if not self.hcl.startswith("#"):
return False
hair_value = self.hcl.replace("#", "")
if len(hair_value) != 6:
return False
try:
_ = int(hair_value, 16)
return True
except ValueError:
return False
def _has_valid_passport_id(self) -> bool:
return (
self.pid is not None
and len(self.pid) == 9
and all([s.isdigit() for s in list(self.pid)])
)
def _is_year_in_range(self, value: NoneString, yr_range: range) -> bool:
if value is None:
return False
if len(value) != 4:
return False
if not value.isdigit():
return False
return int(value) in yr_range
def _read_passports(
instream: typing.BinaryIO,