I want to create a type that represents this dictionary
{
"13fc71ee-e676-4e5d-a561-a20af5bcbaaf": "123",
"8d742ecf-6ae9-4408-a5a0-b1110f9b5365": "fdsafdsa",
"literal": {
"any": "dict",
},
}
This is the closest type I can come up with:
Dict[UUID | Literal["literal"], str | dict]
The main issue with the above type signature is that the following dictionary would be allowed:
{
"8d742ecf-6ae9-4408-a5a0-b1110f9b5365": {
"dictionary": 321,
},
"literal": "some string",
}
Is there a way to annotate a dictionary with a type that can either be a UUID key for a string value or a string literal for a dict value?
CodePudding user response:
What you're asking for potentially requires runtime knowledge and thus cannot be encoded (in a useful way) as a type. Perhaps there is a way to create a custom type that can work with static type checkers for some similar types, but I imagine it would be complicated. Thus, I propose some alternatives:
typing.TypedDict
:
class ItemType(TypedDict):
uuids: dict[str, str]
literal: dict[str, Any]
d: ItemType = {
"uuids": {
"13fc71ee-e676-4e5d-a561-a20af5bcbaaf": "123",
"8d742ecf-6ae9-4408-a5a0-b1110f9b5365": "fdsafdsa",
},
"literal": {
"any": "dict",
},
}
Dataclasses:
@dataclass
class Item:
uuids: dict[str, str]
literal: dict[str, Any]
d = Item(**{
"uuids": {
"13fc71ee-e676-4e5d-a561-a20af5bcbaaf": "123",
"8d742ecf-6ae9-4408-a5a0-b1110f9b5365": "fdsafdsa",
},
"literal": {
"any": "dict",
},
})
Optionally, one can consider overriding __getitem__
to allow dictionary-like access d["literal"]
.
Runtime checks
If all else fails, and you really need to verify constraints that the type system cannot handle, you can do various runtime checks via isinstance
or perhaps via libraries like beartype
.