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

super().__init__ won't accept nested dictionaries when inheriting from DotMap #77

Open
dkrako opened this issue Jul 13, 2021 · 2 comments

Comments

@dkrako
Copy link

dkrako commented Jul 13, 2021

I am using DotMap as the baseclass of a custom Config-class.
As a constructor-argument I only want to pass the path to a yaml-file which holds the config values.

This works quite well if I am just using plain dictionaries without nesting:

from dotmap import DotMap

class ConfigNotNested(DotMap):
    def __init__(self, filepath='config.yaml'):
        # load config-dict from yaml
        config_dict = {'a': 1, 'b': 2}
        super().__init__(config_dict)
print(ConfigNotNested())

Output:

ConfigNotNested(a=1, b=2)

But now with a nested dictionary this stops working:

class ConfigNested(DotMap):
    def __init__(self, filepath='config.yaml'):
        # load config-dict from yaml
        config_dict = {'a': 1, 'b': {'c': 3, 'd': 4}}
        super().__init__(config_dict)
print(ConfigNested())

Output:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-5-87a4fd97b248> in <module>
     11         example = {'a': 1, 'b': {'c': 3, 'd': 4}}
     12         super().__init__(example)
---> 13 print(ConfigNested())

<ipython-input-5-87a4fd97b248> in __init__(self)
     10     def __init__(self):
     11         example = {'a': 1, 'b': {'c': 3, 'd': 4}}
---> 12         super().__init__(example)
     13 print(ConfigNested())

venv/lib/python3.7/site-packages/dotmap/__init__.py in __init__(self, *args, **kwargs)
     46                     else:
     47                         trackedIDs[idv] = v
---> 48                         v = self.__class__(v, _dynamic=self._dynamic, _prevent_method_masking = self._prevent_method_masking, _trackedIDs = trackedIDs)
     49                 if type(v) is list:
     50                     l = []

TypeError: __init__() got an unexpected keyword argument '_dynamic'

Expected output:

ConfigNested(a=1, b=DotMap(c=3, d=4))

I think the problem lies in using self.__class__ instead of DotMap, as this will break on subclassing.
Replacing all self.__class__ occurences with DotMap fixes the issue for me.
I can create a pull request if you don't mind or else I can also implement this in a manner you find more appropriate.

@dkrako
Copy link
Author

dkrako commented Jul 14, 2021

One possible workaround is adding those constructor arguments:

class ConfigNestedWorkaround(DotMap):
    def __init__(self, filepath='config.yaml', **kwargs):
        if type(filepath) in [dict, DotMap]:
            super().__init__(filepath, **kwargs)
            return
        # load config-dict from yaml
        config_dict = {'a': 1, 'b': {'c': 3, 'd': 4}}
        super().__init__(config_dict)
print(ConfigNestedWorkaround())

Output

ConfigNestedWorkaround(a=1, b=ConfigNestedWorkaround(c=3, d=4))

@drgrib
Copy link
Owner

drgrib commented Jul 14, 2021

Hey @cornicis. For sure, I'd be happy to merge a PR that is passing tests and creates a new test for your new feature.

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

2 participants