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
wtf
is used in theexec
's scope but seemingly nowhere else, withexec
itself in a local scope. Thereforewtf
will be a local variable in theexec
scope. Modifications of the locals throughexec
are not visible outside of it, thereforewtf
is not accessible from outside theexec
's scope at all.Names in generator expressions (with the exception of the left-most
for
expression) are evaluated lazily when__next__
is called. Thereforewtf
fromwtf.inbox
will be looked up when__next__
is called.That happens in some other function outside the
exec
scope and thereforewtf
, being local to the latter, is not found there.