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

Accessing any value which is not there in dictionary is printing "DotMap()" #74

Open
mohan-lal opened this issue Jan 29, 2021 · 5 comments
Labels
enhancement needs pr If you want to see this implemented, please submit a PR.

Comments

@mohan-lal
Copy link

mohan-lal commented Jan 29, 2021

After long research, this dotMap module is a lifesaver for me, in my project. Because all other JSON serialize modules end with an error during accessing values especially with multiprocessing call. This module is worth using.

I am facing the below issue with dotMap, could you please help?

    address = {'city': 'abc', 'country': 'XY', 'CountryCode': 101}
    m = DotMap(address)
    print(m.city)
    print(m.CountryCode)
    print(m.zipCode)

Output:
abc
101
DotMap()

In our input JSON, based on need only we will pass somedata(like zipCode), to reduce the load in the payload. But in my back end, in a generic way, we accessing values by doing the null check.

print(m.zipCode) if m.zipCode != ''

but, dotMap is passing 'DotMap()' string if accessing value is not there. How do I fix this? i need to pass it as empty string (''), if the accessing value not there in the dictionary. Appriciate your help on this.

@drgrib
Copy link
Owner

drgrib commented Jan 29, 2021

So it looks like you don't want dynamic child creation. To turn that off, you need to use the constructor with DotMap(_dynamic=False):

address = {'city': 'abc', 'country': 'XY', 'CountryCode': 101}
m = DotMap(address, _dynamic=False)
print(m.city)
print(m.CountryCode)
print(m.zipCode)

which outputs:

abc
101
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/dotmap/__init__.py", line 116, in __getattr__
    return self[k]
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/dotmap/__init__.py", line 93, in __getitem__
    return self._map[k]
KeyError: 'zipCode'

That's the best you can do with the code you've listed. If you want a check, you would need to do:

"zipCode" in m

output:

False

@mohan-lal
Copy link
Author

Thanks for responding. Is there any way to set the last element as ""(empty) instead DotMap() by writing wrapper class to DotMap class.

print(m.address.zipCode.zip1) # assign with ''(empty string) if the zip1 is not there in dictionary.

I tried this, it does not work. It makes parent key itself ''(empty)

    def __getitem__(self, k):
        if k not in self._map and self._dynamic and k != '_ipython_canary_method_should_not_exist_':
            # automatically extend to new DotMap
            self[k] = ''
        return self._map[k]

@drgrib
Copy link
Owner

drgrib commented Jan 30, 2021

I'm sure there is a way to turn DotMap into a default dict the way you are suggesting by supplying it in the constructor like DotMap(_default='') or DotMap(_default=str). This is a redesign that I personally won't have time to implement but I'll review and approve a PR that can pass the current unit tests and adds new unit tests for the feature.

However, to be honest, it sounds to me like the real culprit here is your calling code. I think it makes much more sense to make your calling code more robust to handle the case where the value isn't there than to try to subclass or add a new feature to DotMap. Again, not that I'm opposed to the new feature but it sounds like bad coding practice for your code to assume a value is present in a dynamic data structure without first checking if it is even there.

@mohan-lal
Copy link
Author

mohan-lal commented Jan 30, 2021

The new design would be really helpful for me. Please let me know once the redesign approved.

I completely agreed with you, on our side code practice. Currently, we are using JSON serialize function which is copied in this stack overflow question https://stackoverflow.com/questions/65876256/json-serialized-object-gives-error-with-multiprocessing-calls-typeerror-xxx-o (This question is asked by me). When I take over this application maintenance and enhancement, they already using this functionality to access as dot notation elements and this function will give an empty string "", if that value is not present. Based on this behavior, they have used it in thousands of places in hundreds of documents. Unfortunately, I can't change it everywhere, that's why I am looking to leverage the same behavior(if the value does not present return ""). The problem with this function I used in my project is, not supporting multiprocessing (as mentioned in the stack overflow question). After a lot of research, I found your module is working pretty much with my project. Your module is working very well and supporting parallel processing able to improve performance by 50% on positive cases(if all dict values present). For this negative scenario, seeking help from you. Thanks.

@drgrib
Copy link
Owner

drgrib commented Jan 30, 2021

Just to be clear: I won't be writing the new _default feature and no one is working on it. I was merely expressing my openness to reviewing a PR if someone else wants to write it.

Unfortunately, I've given you all the help I can give. This is a free open source library that I'm simply maintaining because of its popularity. The reality is, I personally stopped using Python regularly long ago and have moved almost entirely to Go.

@FelixSchwarz FelixSchwarz added enhancement needs pr If you want to see this implemented, please submit a PR. labels Dec 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement needs pr If you want to see this implemented, please submit a PR.
Projects
None yet
Development

No branches or pull requests

3 participants