Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Methods like update() and pop() do not manage attributes correctly #3

Open
hindman opened this issue Aug 10, 2014 · 6 comments
Open

Comments

@hindman
Copy link

hindman commented Aug 10, 2014

Methods like update() and pop() do not have the results that I would expect. For example:

# Set up a dict.
In [14]: d = EasyDict(a=1, b=2)
In [15]: d.update(b=22, c=3)
In [16]: d.pop('a')

# This looks good.
In [17]: d
Out[17]: {'b': 22, 'c': 3}

# But attribute d.a is still present, even though we popped it.
In [18]: d.a
Out[18]: 1

# And the call to d.update() did not set up the d.c attribute.
In [19]: d.c
 ---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-19-d731a153f8d9> in <module>()
----> 1 d.c
AttributeError: 'EasyDict' object has no attribute 'c'
@leplatrem
Copy link
Collaborator

Yes, indeed, I confirm :) Thanks for reporting !

This isn't too much work, if you want to give it a try, I would be pleased to review your pull-request !

@LoSealL
Copy link
Contributor

LoSealL commented Oct 16, 2018

@leplatrem Hi, I am happy to submit a PR to fix this issue. However, I would add two functions 'update' and 'pop' to override the builtins, and have to prevent 'update' and 'pop' to be collected in the attribute, like

class EasyDict(dict):
    def __init__(self, d=None, **kwargs):
        if d is None:
            d = {}
        if kwargs:
            d.update(**kwargs)
        for k, v in d.items():
            setattr(self, k, v)
        # Class attributes
        for k in self.__class__.__dict__.keys():
            if not (k.startswith('__') and k.endswith('__')) and not k in ('update', 'pop'):
                setattr(self, k, getattr(self, k))

    def __setattr__(self, name, value):
        if isinstance(value, (list, tuple)):
            value = [self.__class__(x)
                     if isinstance(x, dict) else x for x in value]
        elif isinstance(value, dict) and not isinstance(value, self.__class__):
            value = self.__class__(value)
        super(EasyDict, self).__setattr__(name, value)
        super(EasyDict, self).__setitem__(name, value)

    __setitem__ = __setattr__
    
    def update(self, E=None, **F):
        # Fix update error of easydict
        d = E or dict()
        d.update(F)
        for k in d:
            setattr(self, k, d[k])

    def pop(self, k, d=None):
        delattr(self, k)
        return super(Config, self).pop(k, d)

Does this ok for you?

@leplatrem
Copy link
Collaborator

Thanks @LoSealL for your proposal.

There are a couple of things to adjust in your proposition. It's a lot easier to use the pull requests feature to comment lines of changes. Also you will need to add/modify the tests to assert that your changes don't get broken by some other developers in the future :)

@LoSealL
Copy link
Contributor

LoSealL commented Oct 17, 2018

@leplatrem Yep, made my PR

@Ludecan
Copy link

Ludecan commented Jul 1, 2019

Related to this, I'm having an issue with the pop function. When calling pop with a default value it raises an exception if the key isn't found in the dictionary. The following code reproduces the problem.

from easydict import EasyDict

# Regular dictionary
{'k1': 0}.pop('k2', 1)
# returns 1

# EasyDict is rising an exception
EasyDict({'k1': 0}).pop('k2', 1)
# Traceback (most recent call last):
#  File "<stdin>", line 1, in <module>
#  File ".../lib/python3.5/site-packages/easydict/__init__.py", line 142, in pop
#    delattr(self, k)
# AttributeError: k2

The issue seems related to delatr being called without checking for k's existance?

@La-fe
Copy link

La-fe commented May 7, 2023

def pop(self, k, d=None):
    if hasattr(self, k):
        delattr(self, k)
        return super(EasyDict, self).pop(k, d)
    else:
        return d

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants