A number is also a string. Crazy, right?
#!/usr/bin/env python
import sys
import re
from typing import Annotated
from pydantic import BaseModel, AfterValidator, validator
from pydantic_yaml import parse_yaml_raw_as
def validate_commit_id(s: str) -> str:
assert re.search(r"^[0-9a-f]{9,32}$", s), f"{s} is not a commit id"
return s
CommitId = Annotated[str, AfterValidator(validate_commit_id)]
class Model(BaseModel):
gameServerVersion: CommitId
def main():
text = sys.stdin.read()
conf = parse_yaml_raw_as(Model, text)
print(conf)
if __name__ == "__main__":
main()
It would have prevented the Git Hash Bug originally described: $ cat conf.yaml
gameServerVersion: 556474e378
$ python parse.py < conf.yaml
pydantic_core._pydantic_core.ValidationError: 1 validation error for Model
gameServerVersion
Input should be a valid string [type=string_type, input_value=inf, input_type=float]
$ cat conf.yaml
gameServerVersion: "556474e378"
$ python parse.py < conf.yaml
gameServerVersion='556474e378'
$ cat conf.yaml
gameServerVersion: "Infinity"
$ python parse.py < conf.yaml
pydantic_core._pydantic_core.ValidationError: 1 validation error for Model
gameServerVersion
Assertion failed, Infinity is not a commit id [type=assertion_error, input_value='Infinity', input_type=str]
It's just good practice to validate things on the way in. Even if they were using JSON as their config file, they should still validate it.