user6927293
user6927293

Reputation:

exec: name not defined, but works earlier on in the same code

I ran into this when creating a script that exports dirs and mails to another account with exchangelib.

When I run code with "exec" it returns as not defined but earlier on in the same code it works.

This part doesn't work:

exec('a = van_account.inbox / ' + par + ' / ' + '"%s"' % fol + '; b = a.all().only("id", "changekey"); data = van_account.export(b); up = naar_account.upload((naar_account.inbox / ' + par + ' / ' + '"%s"' % fol + ', d) for d in data); print("[UPLOAD] %i mail geupload in %s" % (len(data), fol))')

This part is right above it and does work. This also refers to "naar_account":

code = "create = Folder(parent=naar_account.inbox / "
par = ' '.join('"{}" /'.format(word) for word in par.split('/'))[:-1]

exec(code + par + ', name="%s"); create.save()' % fol)

This also works:

exec('print(naar_account)')

Even renaming it works and than it says the renamed part is not defined:

exec('wtf = naar_account; a = van_account.inbox / ' + par + ' / ' + '"%s"' % fol + '; b = a.all().only("id", "changekey"); data = van_account.export(b); up = wtf.upload((wtf.inbox / ' + par + ' / ' + '"%s"' % fol + ', d) for d in data); print("[UPLOAD] %i mail geupload in %s" % (len(data), fol))')

Full code:

def search_levels(van_account, naar_account):
    for subfolder in van_account.inbox.walk():
        subfolder = subfolder.absolute

        # If '/' means it has subfolders
        if '/' in subfolder.replace(van_account.inbox.absolute + '/', ''):
            # Strip fill path, leave only Inbox path
            par = subfolder.replace(van_account.inbox.absolute + '/', '')
            # Get last item, it's the Dir we need to create
            fol = par.split('/')[-1]
            # Replace last item, it's the Dir, we only need the parent
            par = par.replace(par.split('/')[-1], '')[:-1]

            code = "create = Folder(parent=naar_account.inbox / "
            par = ' '.join('"{}" /'.format(word) for word in par.split('/'))[:-1]

            exec(code + par + ', name="%s"); create.save()' % fol)
            print('[Created] %s' % fol)

            exec('print(naar_account)')

            exec('a = van_account.inbox / ' + par + ' / ' + '"%s"' % fol + '; b = a.all().only("id", "changekey"); data = van_account.export(b); up = naar_account.upload((naar_account.inbox / ' + par + ' / ' + '"%s"' % fol + ', d) for d in data); print("[UPLOAD] %i mail geupload in %s" % (len(data), fol))')

        else:
            par = None
            fol = subfolder.replace(van_account.inbox.absolute + '/', '')

            create = Folder(parent=naar_account.inbox, name=fol)
            create.save()
            print('[Created] %s' % fol)

            a =  van_account.inbox / fol
            b = a.all().only('id', 'changekey')
            data = van_account.export(b)
            up = naar_account.upload((naar_account.inbox / fol, d) for d in data)
            print('[UPLOAD] %i mail geupload naar %s' % (len(data), fol))

Traceback (most recent call last):
  File "./migrate.py", line 225, in <module>
    start(van_adres, van_passwd, naar_adres, naar_passwd)
  File "./migrate.py", line 114, in start
    search_levels(van_account, naar_account)
  File "./migrate.py", line 154, in search_levels
    exec('a = van_account.inbox / ' + par + ' / ' + '"%s"' % fol + '; b = a.all().only("id", "changekey"); data = van_account.export(b); wtf = naar_account; up = wtf.upload((wtf.inbox / ' + par + ' / ' + '"%s"' % fol + ', d) for d in data); print("[UPLOAD] %i mail geupload in %s" % (len(data), fol))')
  File "<string>", line 1, in <module>
  File "/usr/local/lib/python3.7/site-packages/exchangelib/account.py", line 340, in upload
    is_empty, data = peek(data)
  File "/usr/local/lib/python3.7/site-packages/exchangelib/util.py", line 130, in peek
    first = next(iterable)
  File "<string>", line 1, in <genexpr>
NameError: name 'wtf' is not defined

Upvotes: 0

Views: 190

Answers (1)

walnut
walnut

Reputation: 22152

wtf is used in the exec's scope but seemingly nowhere else, with exec itself in a local scope. Therefore wtf will be a local variable in the exec scope. Modifications of the locals through exec are not visible outside of it, therefore wtf is not accessible from outside the exec's scope at all.

Names in generator expressions (with the exception of the left-most for expression) are evaluated lazily when __next__ is called. Therefore wtf from wtf.inbox will be looked up when __next__ is called.

That happens in some other function outside the exec scope and therefore wtf, being local to the latter, is not found there.

Upvotes: 1

Related Questions