dotsi
dotsi copied to clipboard
Broken hasattr/getattr
Hi there! Cool packages, but run into an issue with it right in the beginning...
from dotsi import DotsiDict
assert getattr({}, "a", None) is None # all good
hasattr(DotsiDict({}), "a") # raises
assert getattr(DotsiDict({}), "a", None) is None # raises
which raises e.g.
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
/var/folders/s5/z9b__9915kq1tpx_kltkywn80000gn/T/ipykernel_40275/4202784131.py in <module>
----> 1 assert getattr(DotsiDict({}), "a", None) is None
KeyError: 'a'
The problem is this line:
__getattr__ = dict.__getitem__
and the core issue is this:
{}["a"]
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
/var/folders/s5/z9b__9915kq1tpx_kltkywn80000gn/T/ipykernel_24098/539066286.py in <module>
----> 1 {}["a"]
KeyError: 'a'
{}.a
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
/var/folders/s5/z9b__9915kq1tpx_kltkywn80000gn/T/ipykernel_24098/3365273685.py in <module>
----> 1 {}.a
AttributeError: 'dict' object has no attribute 'a'
python relies on catching specific exceptions to make hasattr and getattr(obj, key, default_value) work
Potential solution is something like:
def getattr_func(self, attr: str):
try:
return dict.__getitem__(self, attr)
except KeyError as e:
# maybe improve messages to mimic the default one
raise AttributeError(repr(attr)) from e
class DotsiDict(dict):
"Extends `dict` to support dot-access."
def __setitem__(self, key, value): # PRIMARY
super(DotsiDict, self).__setitem__(key, dotsify(value))
__setattr__ = __setitem__
__getattr__ = getattr_func
__delattr__ = dict.__delitem__
# ...
PS for context i run into this because I use iPython/JupyterLab + rich.pretty package to visualise objects:
from rich.pretty import install
install()
DotsiDict({}) # raises error because `rich.pretty` checks for `getattr(object_to_be_displayed, "_repr_html_", None)`