1

I am getting an error message that follows. It indicates that I am misusing an exec because there is some nested function in 'get'. So how can I avoid this issue? My routine works fine in the interactive console, so I don't see what the subfunction is in my code: https://stackoverflow.com/questions/4484872/why-doesnt-exec-work-in-a-function-with-a-subfunction

ERROR    2018-02-16 20:57:49,507 wsgi.py:263] 
Traceback (most recent call last):
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/runtime/wsgi.py", line 240, in Handle
    handler = _config_handle.add_wsgi_middleware(self._LoadHandler())
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/runtime/wsgi.py", line 299, in _LoadHandler
    handler, path, err = LoadObject(self._handler)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/runtime/wsgi.py", line 85, in LoadObject
    obj = __import__(path[0])
  File "/Users/brian/googleapps/c4ica9o/main.py", line 2, in <module>
    from views import MainPageParty, CreateParty, DeleteParty, EditParty, Host, Play, Start, \
SyntaxError: unqualified exec is not allowed in function 'get' it contains a nested function with free variables (views.py, line 132)
INFO     2018-02-16 20:57:49,514 module.py:812] default: "GET /host/BBB HTTP/1.1" 500 -

Python code:

class Host(BaseHandler):

    def get(self, ID):
    key = ndb.Key(Pages,ID,Parties,ID)
    party = key.get()
    tables=party.tables
    rounds=party.rounds
    round_key = 'round'+str(rounds-1)
    table_parent_key = ndb.Key(Pages,ID,Parties,ID,Rounds,round_key).get()
    keys0 = ['p1','p2','p3','p4','s1','s2']
    keys = ['p1','p2','p3','p4','s1','s2','swap']
    dict = {}
    for r in range(rounds):
        round_key = 'round'+str(r)
        names = []
        values = []
        for t in range(tables):
        T=str(t)
        T_key_name = 'table'+T
        table_parent_key = ndb.Key(Pages,ID,Parties,ID,Rounds,round_key,Tables,T_key_name)
        temp = table_parent_key.get()
        if r == 0:
            for k in keys0:
                exec("name='r0t%d%s'"  % (t,k))
                names.append(name)
            for k in keys0:
                exec("value=temp.%s"  % (k))
                values.append(value)
            dict.update({names[i]:values[i] for i in range(len(keys0))})
        else:
            for k in keys:
                exec("name='r%dt%d%s'"  % (r,t,k))
                names.append(name)
            for k in keys:
                exec("value=temp.%s"  % (k))
                values.append(value)
            dict.update({names[i]:values[i] for i in range(len(keys))})
    template_values = {'ID':ID, 'dict': dict}
    template = JINJA_ENVIRONMENT.get_template('host.html')
    self.response.out.write(template.render( template_values))
import webapp2
from views import MainPageParty, CreateParty, DeleteParty, EditParty, Host, Play, Start, \
                    MainPage, CreatePage, DeletePage, EditPage, Unexpected, File, Wifi

app = webapp2.WSGIApplication([
        ('/', MainPage), 
        ('/host/([\w]+)', Host), 
        ],
        debug=True)
zerowords
  • 2,915
  • 4
  • 29
  • 44
  • 2
    What in the ever-loving hell? Why are you creating names via `exec()` and just turning around and throwing them away? – Ignacio Vazquez-Abrams Feb 16 '18 at 21:53
  • 2
    Don't use exec. You can do `name='r0t%d%s' % (t,k)` and `value=getattr(temp, k)`. In general, just don't use exec. – jbch Feb 16 '18 at 21:53
  • I did not know that formatting could be used to make names and I never heard of getattr(). Thanks. – zerowords Feb 16 '18 at 22:04
  • @zerowords I'm not sure what you think you're doing, but `exec("name='foo'")` does the same thing as `name='foo'`. `name` is just a regular variable. – jbch Feb 16 '18 at 22:06
  • To elaborate, there are valid uses for exec but they are rare and very advanced. In a few years of professional Python development I've never had to use exec. You shouldn't use exec unless you know Python very well and you know *exactly* what you are doing. – jbch Feb 16 '18 at 22:10
  • 1
    Also, you are looping over keys 3 times for no good reason, the 7 lines under `if r == 0:` could be replaced by `for k in keys0: dict['r0t%d%s' % (t, k)] = getattr(temp, k)`, and similarly for the lines under `else`. – jbch Feb 16 '18 at 22:17

1 Answers1

1

The nested function is the implicit function created to implement the dict comprehension in

dict.update({names[i]:values[i] for i in range(len(keys))})

Stop using exec. The stuff you're doing with it is pointless and Python 3-incompatible; jbch has posted what you should be doing instead.

Also, stop mixing tabs and spaces. That's also Python 3-incompatible, and it looks very confusing when the display tab width isn't 8 spaces.

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • I'm not familiar with the distinction you make regarding tabs and spaces. I use MacVim and it automatically indents for me but I don't really know whether that indenting is with tabs or spaces. I also sometime edit source and use the key sequences >+> and <+< to adjust indents. Do those key sequences use the opposite of the autoindent, and is that causing the problem you noticed? – zerowords Feb 16 '18 at 22:37
  • @zerowords: I'm not a Vim expert, so I can't tell much about how that mix of tabs and spaces is getting into your code. The people over at https://vi.stackexchange.com/ might know more. – user2357112 Feb 16 '18 at 22:42
  • It would be helpful if you included an explanation WHY the OP should not use exec and what they should use instead. – Jan Pisl Mar 22 '20 at 20:37
  • @JanPisl: Like I said, it's pointless and incompatible with Python 3, and jbch has already pointed out better alternatives. – user2357112 Mar 22 '20 at 22:12
  • (It's also incompatible with the dictionary comprehensions they're using, hence the error.) – user2357112 Mar 22 '20 at 22:19