@Rosuav on the other thread, PEP 505 is stuck in a circle, said that the declarative style of parsing was too onerous because he was only interested in a sub-set of the data. But the sophisticated declarative frameworks like Welcome to Pydantic - Pydantic allow for this. However, maybe Pedantic is too complicated and something simpler, for this use case, could by added to Python instead of .? etc. EG:
# Simple framework as an alternative to `o.?f` and such like.
from dataclasses import dataclass
from typing import Any, get_args, Type, TypeVar
T = TypeVar('T')
@dataclass
class SafeData: # Could be part of Python, maybe a class or decorator in dataclasses.
def __post_init__(self):
for n, t in self.__annotations__.items():
a = getattr(self, n)
t0 = get_args(t)[0] # Minimal expression, real version would have to be better!
if a is None:
if issubclass(t0, SafeData):
setattr(self, n, t0())
elif not isinstance(a, t0):
setattr(self, n, t0.ignoring_extras(a))
@classmethod
def ignoring_extras(cls: Type[T], d: dict[str, Any] | None) -> T:
if d is None:
return cls()
return cls(**{k: d[k] for k in cls.__annotations__.keys() if k in d})
# Example of using the framework by way of some tricky tests!
@dataclass
class F(SafeData):
f: int | None = None
@dataclass
class Safe(SafeData): # Makes safe an external source, like JSON, that might have items missing.
o: F | None = None
tests = [ # Examples of data from an external source that might have bits missing or extra bits.
{"o": {"f": 0}},
{"o": {}},
{"o": None},
{},
None,
{"not_o": {"f": 0}},
{"o": {"not_f": 0}},
]
for test in tests:
safe = Safe.ignoring_extras(test)
print(safe.o.f)
Which produces:
0
None
None
None
None
None
None
The above is easy to add to Python and achieves the goal of making partial traversal of data easy, with no need for new syntax!