Python pull values from nested dictionary for args in function call
<p>So I'm writing a bit of Python code to read in JSON data containing object types and parameters. I essentially need to run through this data and call one of a few functions that, using those parameters, creates a new, unique object each time to be used later. The JSON data looks like this:</p>

<pre><code> {
 "objects" : {
  "1" : {
    "type" : "sphere",
    "radius" : "100",
    "centerx" : "30",
    "centery" : "40",
    "centerz" : "50"
},
  "2" : {
    "type" : "box",
    "lengthx" : "30",
    "lengthy" : "40",
    "lengthz" : "50",
    "centerx" : "60",
    "centery" : "70",
    "centerz" : "80"
},
  "3" : {
    "type" : "cone",
    "length" : "30",
    "radius1" : "40",
    "radius2" : "50",
    "centerx" : "60",
    "centery" : "70",
    "centerz" : "80"
},
  "4" : {
    "type" : "cylinder",
    "length" : "30",
    "radius" : "40",
    "centerx" : "60",
    "centery" : "70",
    "centerz" : "80"
    }
   }
}
</code></pre>

<p>Here's my updated code as it stands now:</p>

<pre><code>display, start_display, add_menu, add_function_to_menu = init_display()
with open('C:\Users\willi_000\Documents\Code\document (9).json') as   data_file:
    data = json.load(data_file)

funcs = {
    'sphere': BRepPrimAPI_MakeSphere,
    'box': BRepPrimAPI_MakeBox,
    'cone': BRepPrimAPI_MakeCone,
    'cylinder': BRepPrimAPI_MakeCylinder
}
shapes = []
for index, kwargs in data['objects'].iteritems():
    mypoint = gp_Pnt(float(kwargs.pop('centerx')),     float(kwargs.pop('centery')), float(kwargs.pop('centerz')))
    function = funcs[kwargs.pop('type')]
    #print mypoint
    #print function
    myshape = function(mypoint,float(**kwargs)).Shape()
    start_display() 
</code></pre>

<p>And night now I'm getting the following error</p>

<pre><code>Traceback (most recent call last):
  File "C:/Users/willi_000/Documents/Code/dumbbox.py", line 32, in &lt;module&gt;
    myshape = function(mypoint,**kwargs).Shape()
TypeError: keywords must be strings"
</code></pre>

<p>For reference, here are two examples of what the make functions are expecting</p>

<pre><code>BRepPrimAPI_MakeSphere::BRepPrimAPI_MakeSphere  (   const gp_Pnt &amp;  Center,
const Standard_Real     R )     


BRepPrimAPI_MakeBox::BRepPrimAPI_MakeBox    (   const gp_Pnt &amp;  P,
const Standard_Real     dx,
const Standard_Real     dy,
const Standard_Real     dz )    
</code></pre>

<p>This will add all of the <code>Shapes</code> to a list. </p>

<pre><code>data ={
 "objects" : {
  "1" : {
    "type" : "sphere",
    "radius" : "100",
    "centerx" : "30",
    "centery" : "40",
    "centerz" : "50"
},
  "2" : {
    "type" : "box",
    "lengthx" : "30",
    "lengthy" : "40",
    "lengthz" : "50",
    "centerx" : "60",
    "centery" : "70",
    "centerz" : "80"
},
  "3" : {
    "type" : "cone",
    "length" : "30",
    "radius1" : "40",
    "radius2" : "50",
    "centerx" : "60",
    "centery" : "70",
    "centerz" : "80"
},
  "4" : {
    "type" : "cylinder",
    "length" : "30",
    "radius" : "40",
    "centerx" : "60",
    "centery" : "70",
    "centerz" : "80"
    }
   }
}

funcs = {
    'sphere': BRepPrimAPI_MakeSphere,
    'box': BRepPrimAPI_MakeBox,
    'cone': BRepPrimAPI_MakeCone,
    'cylinder': BRepPrimAPI_MakeCylinder
}
shapes = []
for index, kwargs in data['objects'].iteritems():
    function = funcs[kwargs.pop('type')]
    shapes.append(function(**kwargs).Shape())
</code></pre>

<p>I had to fake the functions and the <code>.Shape()</code> part, but it works for me.</p>

<hr>

<h2>Update</h2>

<p>As per the comment (by @williamwatts), I think this is what you want. Replace the <code>for</code> loop with this:</p>

<pre><code>for index, kwargs in data['objects'].iteritems():
    function = funcs[kwargs.pop('type')]
    kwargs = {k:float(v) for k, v in kwargs.iteritems()}
    mypoint = gp_Pnt(kwargs.pop('centerx'), kwargs.pop('centery'), kwargs.pop('centerz'))
    myshape = function(mypoint, **kwargs).Shape()
    shapes.append(myshape)
    display.DisplayShape(myshape, update=True)
</code></pre>

<p>This assumes that all shapes will have <code>centerx</code>, <code>centery</code> and <code>centerz</code> attributes.</p>

<hr>

<h2>Update 2</h2>

<p>Since the functions are defined using *args, you cannot use keyword arguments. You will have to use this instead:</p>

<pre><code>funcs = {
    'sphere': {
        'function': BRepPrimAPI_MakeSphere,
        'argnames': ['radius']
    },
    'box': {
        'function': BRepPrimAPI_MakeBox,
        'argnames': ['lengthx', 'lengthy', 'lengthz']
    },
    'cone': {
        'function': BRepPrimAPI_MakeCone,
        'argnames': ['length', 'radius1', 'radius2']
    },
    'cylinder': {
        'function': BRepPrimAPI_MakeCylinder,
        'argnames': ['length', 'radius']
    }
}
shapes = []
for index, kwargs in data['objects'].iteritems():
    print kwargs
    shapeinfo = funcs[kwargs.pop('type')]
    kwargs = {k:float(v) for k, v in kwargs.iteritems()}
    mypoint = gp_Pnt(kwargs.pop('centerx'), kwargs.pop('centery'), kwargs.pop('centerz'))
    args = [kwargs[name] for name in shapeinfo['argnames']]
    myshape = shapeinfo['function'](mypoint, *args).Shape()
    shapes.append(myshape)
    display.DisplayShape(myshape, update=True)
</code></pre>

<p>This makes sure that the args are sent in the correct order.</p>

python json dictionary