def main(ctx, interactive, suppress_output, no_temp_profile, generate_docs, only_document_plugins, omit_header, debug, version, debugger_url, log_level, script_log_level, plugins, script, remainder): if version is True: print('webfriend {}'.format(webfriend.info.version)) sys.exit(0) log.setLevel(logging.getLevelName(log_level.upper())) if plugins: plugins = plugins.split(',') if generate_docs: click.echo('\n'.join( document_commands(plugins=plugins, only_plugins=only_document_plugins, omit_header=omit_header))) else: if debug: os.environ['WEBFRIEND_DEBUG'] = 'true' if not interactive and script is None and sys.stdin.isatty(): raise IOError("Must provide the path to script to execute.") # using the with-syntax launches an instance of chrome in the background before proceeding with Chrome(debug_url=debugger_url, use_temp_profile=(not no_temp_profile)) as chrome: environment = Environment(browser=chrome, log_level=script_log_level) if isinstance(plugins, list): for plugin in plugins: environment.register_by_module_name(plugin) # interactive REPL if interactive: repl = REPL(chrome, environment=environment) repl.run() else: # by now we've validated that there is not a TTY waiting at stdin, so there # must be some data to read. In that case, read the script from stdin. # # This let's users call `webfriend` by piping commands to it or by passing in heredocs # scriptpath = os.getcwd() if script is None: script = sys.stdin else: scriptpath = os.path.abspath(os.path.dirname(script.name)) # execute script as file (or via shebang invocation) scope = execute_script(chrome, script.read(), environment=environment, scriptpath=scriptpath).as_dict() if not suppress_output: click.echo(json.dumps(scope, indent=4))
def execute_script(self, script, scope=None): """ Execute an automation script against this browser session. Args: script (str): The full text of the script to execute. scope (`webfriend.scripting.Scope`, optional): An optional initial scope to execute the script from. This can be used to provide the script with initial values for variables used in the script. """ return execute_script(self, script, scope)
def _eval(self, script): return execute_script(None, script).as_dict()
def run( self, script_name, data=None, isolated=True, preserve_state=True, merge_scopes=False, result_key=Environment.default_result_key ): """ Evaluates another Friendscript loaded from another file. #### Arguments - **script_name** (`str`): The filename or basename of the file to search for in the `WEBFRIEND_PATH` environment variable to load and evaluate. The `WEBFRIEND_PATH` variable behaves like the the traditional *nix `PATH` variable, wherein multiple paths can be specified as a colon-separated (`:`) list. The current working directory will always be checked first. - **data** (`dict`, optional): If specified, these values will be made available to the evaluated script before it begins execution. - **isolated** (`bool`): Whether the script should have access to the calling script's variables or not. - **preserve_state** (`bool`): Whether event handlers created in the evaluated script should remain defined after the script has completed. - **merge_scopes** (`bool`): Whether the scope state at the end of the script's evaluation should be merged into the current execution scope. Setting this to true allows variables defined inside of the evaluated script to stay defined after the script has completed. Otherwise, only the value of the **result_key** variable is returned as the result of this command. - **result_key** (`str`): Defines the name of the variable that will be read from the evaluated script's scope and returned from this command. Defaults to "result", which is the same behavior as all other commands. #### Returns The value of the variable named by **result_key** at the end of the evaluated script's execution. #### Raises Any exception that can be raised from Friendscript. """ script = None final_script_name = None path_prefixes = ['.'] # makes the ".fs" optional when passing scripts as arguments script_name = re.sub(r'\.fs$', '', script_name) + '.fs' # setup scopes if isolated: scope = Scope() else: scope = Scope(parent=self.scope) # if data is specified, set these values in the evaluated script's scope if isinstance(isolated, dict): scope.update(isolated) # process WEBFRIEND_PATH envvar for prefix in os.environ.get('WEBFRIEND_PATH', '').split(':'): path_prefixes.append(prefix) # search for file in all prefixes for prefix in path_prefixes: s = os.path.join(prefix, script_name) if os.path.isfile(s): final_script_name = s script = open(final_script_name, 'r').read() break # validate the script was read if script is None: raise exceptions.NotFound('Unable to locate script "{}" in any path'.format( script_name )) elif isinstance(script, str): script = script.decode('UTF-8') # evaluate the script logging.debug('Evaluating script {}'.format(final_script_name)) scope = execute_script( self.browser, script, scope=scope, preserve_state=preserve_state ) # if not using an isolated scope, then the top-level keys that were modified in this script # are set in our current scope (as if the included code ran inline) if merge_scopes: logging.debug( 'Updating {} variables in calling scope with result scope (iso={})'.format( len(scope), isolated ) ) self.scope.update(scope) return scope.get('result')