My question is tied to Dan Bader's schedule package. From what I understand, you schedule function calls. That's pretty simple if you are defining the function in your script. However, what about functions that are built dynamically using exec()? Is there any way to make these callable? I keep getting errors when trying to schedule these functions. I recognize that this is likely not the best idea (maybe not even a good idea), but this is just for a POC and I'm still curious if this can be done.
def buildJob(lang, repType, name, file='', recipient='', server = '', db='', path=''):
today = datetime.datetime.strftime(datetime.datetime.today(), '%m%d%Y%H%M%S')
filePath = f"{c.path}{name}-{today}".replace('\\', '/')
filename = f'{name}-{today}.xlsx'
funcText = f"""
def {name}():
sql = ("{file}")
filePath = ("{filePath}")
engine = sa.create_engine(conString)
dat = pd.read_sql_query(sql, engine)
engine.dispose()
del engine
buildSpreadsheet(dat, filePath)
sendSpreadsheet("{recipient}", "{filePath}.xlsx", "{filename}")
"""
I then have a function to grab the funcText and exec() it. However, when I pass this into schedule, it says that the argument must be callable.
Any help would be greatly appreciated!
1 Answer 1
You can retrieve defined functions with the locals() and globals() dicts.
# in global scope
as_str = f"""
def foo():
print('foo')
"""
exec(as_str)
foo = globals()['foo']
foo()
# in function scope
def bar():
as_str = f"""
def baz():
print('baz')
"""
exec(as_str)
return locals()['baz']
baz = bar()
baz()
Someone may correct me but dynamic function creation with exec seems like a bad idea. Especially if the input isn't being sanitized.
globals()['function_name']?namedtupleclass was originally defined in a similar fashion, constructing a giantclassstatement executed byexec. It was eventually re-implemented in C for performance, but as a POC, it's not a terrible starting point.)exec()occurring? If it's within a function it will be in local scope.