Skip to content

Broken hasattr/getattr #3

@caenrigen

Description

@caenrigen

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)`

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions