Source code for stressor.plugins.script_activities
# (c) 2020-2024 Martin Wendt and contributors; see https://github.com/mar10/stressor# Licensed under the MIT license: https://www.opensource.org/licenses/mit-license.php""""""frompprintimportpformatfromtextwrapimportdedentfromstressor.plugins.baseimport(ActivityBase,ActivityCompileError,ScriptActivityError,)fromstressor.utilimportNO_DEFAULT,check_arg,logger,shorten_string
[docs]classRunScriptActivity(ActivityBase):_mandatory_args=None_known_args={"export","path","script"}_info_args=("name","path")def__init__(self,config_manager,**activity_args):""""""super().__init__(config_manager,**activity_args)path=activity_args.get("path")script=activity_args.get("script")# Allow to pass `export: null` to define 'no export wanted'# (omitting the argumet is considered 'undefined' and will emit a# warning if the script produces variables)export=activity_args.get("export",NO_DEFAULT)ifexportin(None,False):export=tuple()elifexportisNO_DEFAULT:export=Nonecheck_arg(path,str,or_none=True)check_arg(script,str,or_none=True)check_arg(export,(str,list,tuple),or_none=True)ifpath:ifscript:raiseActivityCompileError("`path` and `script` args are mutually exclusive")path=config_manager.resolve_path(path)withopen(path)asf:script=f.read()#:self.script=compile(script,path,"exec")elifscript:# script = dedent(self.script)self.script=compile(script,"<string>","exec")else:raiseActivityCompileError("Either `path` or `script` expected")#: Store a shortened code snippet for debug outputself.source=shorten_string(dedent(script),500,100)# print(self.source)ifexportisNone:self.export=Noneelifisinstance(export,str):self.export=set((export,))else:self.export=set(export)return
[docs]defexecute(self,session,**expanded_args):""""""global_vars={# "foo": 41,# "__builtins__": {},}# local_vars = session.contextlocal_vars=session.context.copy()assert"result"notinlocal_varsassert"session"notinlocal_varslocal_vars["session"]=session.make_session_helper()# prev_local_keys = set(locals())prev_global_keys=set(globals())prev_context_keys=set(local_vars.keys())try:exec(self.script,global_vars,local_vars)exceptConnectionErrorase:# TODO: more requests-exceptions?msg=f"Script failed: {e!r}: {e}"raiseScriptActivityError(msg)exceptExceptionase:msg=f"Script failed: {e!r}: {e}"ifsession.verbose>=4:logger.exception(msg)raiseScriptActivityError(msg)fromeraiseScriptActivityError(msg)finally:local_vars.pop("session")result=local_vars.pop("result",None)context_keys=set(local_vars.keys())new_keys=context_keys.difference(prev_context_keys)ifnew_keys:ifself.exportisNone:logger.info("Skript activity has no `export` defined. Ignoring new variables: '{}'".format("', '".join(new_keys)))else:forkinself.export:v=local_vars.get(k)asserttype(v)in(int,float,str,list,dict)session.context[k]=vlogger.debug(f"Set context.{k} = {v!r}")# store_keys = new_keys.intersection(self.export)# TODO: this cannot happen?new_globals=set(globals().keys()).difference(prev_global_keys)ifnew_globals:logger.warning(f"Script-defined globals: {new_globals}")raiseScriptActivityError("Script introduced globals")# new_context = context_keys.difference(prev_context_keys)# logger.info("Script-defined context-keys: {}".format(new_context))# new_locals = set(locals().keys()).difference(prev_local_keys)# if new_locals:# logger.info("Script-defined locals: {}".format(new_locals))# logger.info("Script locals:\n{}".format(pformat(local_vars)))ifexpanded_args.get("debug")orsession.verbose>=5:logger.info(f"{session.context_stack}{self}\n Context after execute:\n{pformat(session.context,indent=4)}\n return value: {result!r}")elifsession.verbose>=3andresultisnotNone:logger.info(f"{session.context_stack} returnd: {shorten_string(result,200)ifisinstance(result,str)elseresult!r}")returnresult