1

I am trying to write a dynamic program(to parse json files based on their tags) in python and i am using Python exec function to do that. But the program is failing when exec statement is in a function.

RUN 1: Exec in a function:

import json
from pandas.io.json import json_normalize
import sys
def param(dfile):
    aString = "['widget']['image']~['widget']['window']~['widget']['text']"
    for nd_part in aString.split('~'):
        exec("temp = %s%s"%(dfile,nd_part))
        print(temp)
if __name__ == "__main__":
    dfile = json.load(open("sample_json.json"))
    str_list = param(dfile)

JSON Data: sample_json.json

{"widget": {
    "debug": "on",
    "window": {
        "title": "Sample Konfabulator Widget",
        "name": "main_window",
        "width": 500,
        "height": 500
    },
    "image": {
        "src": "Images/Sun.png",
        "name": "sun1",
        "hOffset": 250,
        "vOffset": 250,
        "alignment": "center"
    },
    "text": {
        "data": "Click Here",
        "size": 36,
        "style": "bold",
        "name": "text1",
        "hOffset": 250,
        "vOffset": 100,
        "alignment": "center",
        "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
    }
}}

Error:

Traceback (most recent call last):
  File "sample_test_json.py", line 12, in <module>
    str_list = param(dfile)
  File "sample_test_json.py", line 9, in param
    print(temp)
NameError: name 'temp' is not defined

RUN 2: EXEC in main:

import json
from pandas.io.json import json_normalize
import sys
if __name__ == "__main__":
    dfile = json.load(open("sample_json.json"))
    aString = "['widget']['image']~['widget']['window']~['widget']['text']"
    for nd_part in aString.split('~'):
        exec("temp = %s%s"%(dfile,nd_part))
        print(temp)

JSON Data: sample_json.json(same data as above)

Output: No error(Result as expected)

{'hOffset': 250, 'vOffset': 250, 'name': 'sun1', 'alignment': 'center', 'src': 'Images/Sun.png'}
{'width': 500, 'height': 500, 'name': 'main_window', 'title': 'Sample Konfabulator Widget'}
{'data': 'Click Here', 'hOffset': 250, 'vOffset': 100, 'size': 36, 'style': 'bold', 'onMouseUp': 'sun1.opacity = (sun1.opacity / 100) * 90;', 'name': 'text1', 'alignment': 'center'}

RUN 3: I tried eval and tried formatting the string from this post. How to return value from exec in function?

import json
from pandas.io.json import json_normalize
import sys
def param(dfile):
    aString = "['widget']['image']~['widget']['window']~['widget']['text']"
    for nd_part in aString.split('~'):
        exec('temp = "{}""{}"'.format(dfile,nd_part))
        print(temp)
if __name__ == "__main__":
    dfile = json.load(open("sample_json.json"))
    str_list = param(dfile)

Error:

Traceback (most recent call last):
  File "sample_test_json.py", line 12, in <module>
    str_list = param(dfile)
  File "sample_test_json.py", line 9, in param
    print(temp)
NameError: name 'temp' is not defined

Please help me in identifying the issue. Thanks in advance.

goks
  • 1,196
  • 3
  • 18
  • 37
  • 2
    You will probably have better luck using `eval()` but really, there's no need for that either. – kindall Oct 16 '17 at 15:51
  • You're just trying to set the variable. There's no need for `exec()` – Cfreak Oct 16 '17 at 15:52
  • yes. But my original requirement is to create a dataframe from each tag and write into delimiter file. My program should be dynamic to handle multiple tags and create multiple files base on number of tags (planning to pass those tags as paramaters to this program). – goks Oct 16 '17 at 15:54
  • @kindall let me try eval() – goks Oct 16 '17 at 16:14
  • Thanks @kindall. eval() is working. I will post my answer – goks Oct 16 '17 at 16:17
  • Can someone please explain exec() function behaviour in RUN1 vs RUN2 above? – goks Oct 19 '17 at 14:52

2 Answers2

1

Using Eval() i am getting the result i exepcted. Posting answer below. But still i am not sure why exec() is not working.

import json
from pandas.io.json import json_normalize
import sys
def param(dfile):
    aString = "['widget']['image']~['widget']['window']~['widget']['text']"
    for nd_part in aString.split('~'):
        s = '{0}{1}'.format('dfile',nd_part)
        temp = eval(s)
        print(temp)
if __name__ == "__main__":
    dfile = json.load(open("sample_json.json"))
    str_list = param(dfile)

Result:

{'src': 'Images/Sun.png', 'alignment': 'center', 'vOffset': 250, 'name': 'sun1', 'hOffset': 250}
{'title': 'Sample Konfabulator Widget', 'height': 500, 'width': 500, 'name': 'main_window'}
{'alignment': 'center', 'onMouseUp': 'sun1.opacity = (sun1.opacity / 100) * 90;', 'data': 'Click Here', 'hOffset': 250, 'size': 36, 'vOffset': 100, 'name': 'text1', 'style': 'bold'}
goks
  • 1,196
  • 3
  • 18
  • 37
1

I think exec add temp to global. So add global temp before print temp may be useful

import json
from pandas.io.json import json_normalize
import sys
def param(dfile):
    global temp
    aString = "['widget']['image']~['widget']['window']~['widget']['text']"
    for nd_part in aString.split('~'):
        exec("temp = %s%s"%(dfile,nd_part))
        print(temp)
if __name__ == "__main__":
    dfile = json.load(open("sample_json.json"))
    str_list = param(dfile)

should be fine.

Or you can also do things like

import json
from pandas.io.json import json_normalize
import sys
def param(dfile):
    d={}
    aString = "['widget']['image']~['widget']['window']~['widget']['text']"
    for nd_part in aString.split('~'):
        exec("temp = %s%s"%(dfile,nd_part),d)
        print(d['temp'])
if __name__ == "__main__":
    dfile = json.load(open("sample_json.json"))
    str_list = param(dfile)
The_book
  • 11
  • 2
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 30 '22 at 03:11
  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/31404756) – vvvvv Mar 31 '22 at 12:55