Once I got around to finding out how to do this with Pydantic, I found it is exceedingly easy, at least as long as you are dealing with such a small difference between the two structures. You'll need to install pydantic to try the following working example:
from pydantic import BaseModel, Field
class Animal(BaseModel):
genus: str = Field(alias="breed")
color: str
name: str
class Config:
allow_population_by_field_name = True
spot = Animal(genus = "retriever"genus="retriever", color = "brown"color="brown", name = "spot"name="spot")
json_v1 = spot.json(by_alias=True)
json_v2 = spot.json()
print("v1 out:", json_v1)
print("v2 out:", json_v2)
animal_v1 = Animal.parse_raw(json_v1)
animal_v2 = Animal.parse_raw(json_v2)
print("v1 in:", animal_v1)
print("v2 in:", animal_v2)
Output:
v1 out: {"breed": "retriever", "color": "brown", "name": "spot"}
v2 out: {"genus": "retriever", "color": "brown", "name": "spot"}
v1 in: genus='retriever' color='brown' name='spot'
v2 in: genus='retriever' color='brown' name='spot'
If you aren't familiar with Pydantic, it builds upon dataclasses to add a lot of really useful features. Every time I dig into it, I find more interesting things. I even used it recently to help me generate an antiquated wire format that you can't get libraries for, at least not for free. I've wrestled with serialization for decades and it's a really good tool. Other really good frameworks like FastAPI are built upon it as well.