pycrdt
pycrdt copied to clipboard
getattr with default value can raise an error
When trying to use getattr with a default argument on any object inheriting from Typed, a KeyError will be raised instead of returning the default value.
_check_key, _map.py:267
__getitem__, _map.py:156
__getattr__, _base.py:380
This come from the function Map._check_key that will raise a KeyError if a key is not present in the map. It is called by its own __getitem__, used by TypedMap.__getattr__.
The issue is that for getattr to use the default value, an AttributeError must be raised instead. This can be easily fixed by rethrowing the error in Typed.__getattr__ with the correct type.
Original function :
def __getattr__(self, key: str) -> Any:
annotations = self.__dict__["annotations"]
if key not in annotations:
raise AttributeError(f'"{type(self).mro()[0]}" has no attribute "{key}"')
expected_type = annotations[key]
if hasattr(expected_type, "mro") and Typed in expected_type.mro():
return expected_type(self._[key])
return self._[key]
Updated function :
def __getattr__(self, key: str) -> Any:
annotations = self.__dict__["annotations"]
if key not in annotations:
raise AttributeError(f'"{type(self).mro()[0]}" has no attribute "{key}"')
expected_type = annotations[key]
if hasattr(expected_type, "mro") and Typed in expected_type.mro():
try:
return expected_type(self._[key])
except KeyError:
raise AttributeError(f'"{type(self).mro()[0]}" has no attribute "{key}"')
return self._[key]