drgrib / dotmap

Dot access dictionary with dynamic hierarchy creation and ordered iteration
MIT License
466 stars 44 forks source link

Can't use DotMap with exec? #56

Open frdfsnlght opened 4 years ago

frdfsnlght commented 4 years ago

Here's some sample code:

from dotmap import DotMap

code = 'print("hello")'
g = {}
l = DotMap()
exec(code, g, l)

And it's output (using python 3.7.3 on Raspbian):

Traceback (most recent call last):
  File "dotmaptest.py", line 7, in <module>
    exec(code, g, l)
  File "<string>", line 1, in <module>
TypeError: 'DotMap' object is not callable

Any idea why I can't use a DotMap as the "locals" parameter? Using a standard dictionary works, of course. I can't seem to find any obvious answer, but maybe I'm missing something.

drgrib commented 4 years ago

Strange. The locals argument in exec() is supposed to accept a mapping object and as far as I know, DotMap is one. But maybe I'm wrong about that.

In the meanwhile, a usable, if slightly cumbersome, workaround is

from dotmap import DotMap

code = 'print("hello")'
g = {}
l = DotMap()
exec(code, g, l.toDict())
frdfsnlght commented 4 years ago

That's about where I've arrived as well. However, I don't think it will work for my use case. Correct me if I'm wrong, but changes made the dictionary (in the code being exec'ed) that result from l.toDict() won't propagate back to the DotMap? Maybe I could just create a new DotMap from the changed dictionary, but I get worried about all the conversions back and forth taking up "too much time". I don't know what "too much time" means for my situation, but I'm trying to keep the part of the code that needs to do the exec as fast as possible.

You're findings on the requirements of the local parameter to the exec function are also what I found and caused me to scratch my head. Looking at the DotMap code (and since it inherits from dict) it looks like it satisfies the requirements. I don't understand what's going on. Maybe the python source needs to be consulted?

drgrib commented 4 years ago

Yes, if you need the code in the exec call to update the values in the locals DotMap, then the toDict solution won't work.

Checking the exec source code is probably the next step, though not one that I personally have the bandwidth to explore.

frdfsnlght commented 4 years ago

Well, I just spent some time looking at the python source for exec and following it to the best of my abilities and I'm no closer to understanding what's wrong.

Adding DotMap to my project was just a nice feature to have but unnecessary. I'll probably have to drop it unless I can think of some other clever solution. I have a bunch more development to do anyway.

Thanks.

MaxOstrowski commented 1 year ago

Just encountered the same problem. Any new insights on this issue ? Thanks a lot.

drgrib commented 1 year ago

No new insights. Full disclosure, I support DotMap as much as I can in my spare time using my past experience in Python and general programming and algorithms knowledge. But I don't even use Python for active development anymore, let alone DotMap specifically. So involved Python-specific debugging like this is way out of scope for my personal attention.

MaxOstrowski commented 1 year ago

This code

from dotmap import DotMap

#x = {}
x = DotMap()
exec("print(42)", {}, x)

fails with the DotMap with the Error: TypeError: 'DotMap' object is not callable Other instructions, like

from dotmap import DotMap

#x = {}
x = DotMap()
exec("a=42", {}, x)

work fine. The problem is the function call to print. In fact, this is true for any other function call, like: exec("list([])", {}, x) DotMap seems to try to generate "list" or "print" as an entry to the dictionary. Edit: Using DotMap(_dynamic=False) makes the code work again.

I think this should be fine for my current usecase, maybe it helps others, and maybe it helps to identify where the bug is ?