drgrib / dotmap

Dot access dictionary with dynamic hierarchy creation and ordered iteration

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Dictionary extraction such as c = {**a, **b} not functioning properly.

heetbeet opened this issue · comments

The following was tested on Linux Mint 17, Python version Python 3.6.2 :: Anaconda custom (64-bit) and dotmap version sys.version_info(major=3, minor=6, micro=2, releaselevel='final', serial=0)

  1. (lambda **x:x)(**DotMap(a=1)) returns an unexpected empty dictionary {},
  2. {**DotMap(a=1),**DotMap(b=2)} returns an unexpected empty dictionary {}, and
  3. m = DotMap(); m.a = 2; m.b = 3; print('{a} {b}'.format(**m)); fails with KeyError: 'a'.

Other functionality is working properly such as:

  1. DotMap(a=1)['a'] returns an expected 1, and
  2. DotMap(a=1).a returns an expected 1.

@heetbeet I'm not able to reproduce item 3, but I can reproduce 1 and 2.

The issue seems to be that, because DotMap inherits from OrderedDict, its own implementations for

  • __len__
  • __iter__
  • __getitem__

are being ignored in these particular types of ** calls and instead being called for the parent OrderedDict class.

I can fix your cases by removing that inheritance and only having it inherit from MutableMapping but that breaks a unit test in __main__ with the title == copy order preservation ==.

If you have immediate suggestions, I'm open to them. Otherwise, I'll have to debug this at a later time.

@drgrib I see. I switched over to the following implementation for my dot dictionary needs (I know it clashes for keys that are the same as the dictionary names - such as "pop", "update", "keys", "values", etc.):

class DotDict(dict):
    def __init__(self, **kwds):
        self.update(kwds)
        self.__dict__ = self

So I am not in an immediate need for fixes. I'll switch back to DotMap in the future when doing a bit of code refactoring and the pip default is working nicely again. Thanks for the trouble.

Shortest test on python2.7.13 for this issue:

>>> dict(**dotmap.DotMap(a=1))
{}

When using ** a lot this means DotMap fails as a dropin replacement for dictionaries. And it would be so nice to have just that.

I've given this multiple shots and it's honestly too complicated to be worth the trouble when there is a simple workaround available already:

>>> dict(**dotmap.DotMap(a=1).toDict())
{'a': 1}

More on why completely acing the subclass in this manner is so difficult here.

Fixed in #53