Best Python code snippet using avocado_python
nrunner.py
Source:nrunner.py  
...83        return cls(args.get('kind'),84                   args.get('uri'),85                   *decoded_args,86                   config=json.loads(args.get('config', '{}')),87                   **_key_val_args_to_kwargs(args.get('kwargs', [])))88    @classmethod89    def from_recipe(cls, recipe_path):90        """91        Returns a runnable from a runnable recipe file92        :param recipe_path: Path to a recipe file93        :rtype: instance of :class:`Runnable`94        """95        with open(recipe_path) as recipe_file:96            recipe = json.load(recipe_file)97        return cls(recipe.get('kind'),98                   recipe.get('uri'),99                   *recipe.get('args', ()),100                   config=recipe.get('config', {}),101                   **recipe.get('kwargs', {}))102    def get_command_args(self):103        """104        Returns the command arguments that adhere to the runner interface105        This is useful for building 'runnable-run' and 'task-run' commands106        that can be executed on a command line interface.107        :returns: the arguments that can be used on an avocado-runner command108        :rtype: list109        """110        args = ['-k', self.kind]111        if self.uri is not None:112            args.append('-u')113            args.append(self.uri)114        if self.config is not None:115            args.append('-c')116            args.append(json.dumps(self.config))117        for arg in self.args:118            args.append('-a')119            if arg.startswith('-'):120                arg = 'base64:%s' % base64.b64encode(arg.encode()).decode('ascii')121            args.append(arg)122        if self.tags is not None:123            args.append('tags=json:%s' % json.dumps(self.get_serializable_tags()))124        for key, val in self.kwargs.items():125            if not isinstance(val, str) or isinstance(val, int):126                val = "json:%s" % json.dumps(val)127            args.append('%s=%s' % (key, val))128        return args129    def get_dict(self):130        """131        Returns a dictionary representation for the current runnable132        This is usually the format that will be converted to a format133        that can be serialized to disk, such as JSON.134        :rtype: :class:`collections.OrderedDict`135        """136        recipe = collections.OrderedDict(kind=self.kind)137        if self.uri is not None:138            recipe['uri'] = self.uri139        recipe['config'] = self.config140        if self.args is not None:141            recipe['args'] = self.args142        kwargs = self.kwargs.copy()143        if self.tags is not None:144            kwargs['tags'] = self.get_serializable_tags()145        if kwargs:146            recipe['kwargs'] = kwargs147        return recipe148    def get_json(self):149        """150        Returns a JSON representation151        :rtype: str152        """153        return json.dumps(self.get_dict())154    def get_serializable_tags(self):155        tags = {}156        # sets are not serializable in json157        for key, val in self.tags.items():158            if isinstance(val, set):159                val = list(val)160            tags[key] = val161        return tags162    def write_json(self, recipe_path):163        """164        Writes a file with a JSON representation (also known as a recipe)165        """166        with open(recipe_path, 'w') as recipe_file:167            recipe_file.write(self.get_json())168    def is_kind_supported_by_runner_command(self, runner_command):169        """Checks if a runner command that seems a good fit declares support."""170        cmd = runner_command + ['capabilities']171        try:172            process = subprocess.Popen(cmd,173                                       stdin=subprocess.DEVNULL,174                                       stdout=subprocess.PIPE,175                                       stderr=subprocess.DEVNULL)176        except (FileNotFoundError, PermissionError):177            return False178        out, _ = process.communicate()179        try:180            capabilities = json.loads(out.decode())181        except json.decoder.JSONDecodeError:182            return False183        return self.kind in capabilities.get('runnables', [])184    def pick_runner_command(self, runners_registry=None):185        """Selects a runner command based on the runner.186        And when finding a suitable runner, keeps found runners in registry.187        This utility function will look at the given task and try to find188        a matching runner.  The matching runner probe results are kept in189        a registry (that is modified by this function) so that further190        executions take advantage of previous probes.191        This is related to the :data:`SpawnMethod.STANDALONE_EXECUTABLE`192        :param runners_registry: a registry with previously found (and not193                                 found) runners keyed by runnable kind194        :param runners_registry: dict195        :returns: command line arguments to execute the runner196        :rtype: list of str or None197        """198        if runners_registry is None:199            runners_registry = RUNNERS_REGISTRY_STANDALONE_EXECUTABLE200        runner_cmd = runners_registry.get(self.kind)201        if runner_cmd is False:202            return None203        if runner_cmd is not None:204            return runner_cmd205        standalone_executable_cmd = ['avocado-runner-%s' % self.kind]206        if self.is_kind_supported_by_runner_command(standalone_executable_cmd):207            runners_registry[self.kind] = standalone_executable_cmd208            return standalone_executable_cmd209        # attempt to find Python module files that are named after the210        # runner convention within the avocado.core namespace dir.211        # Looking for the file only avoids an attempt to load the module212        # and should be a lot faster213        core_dir = os.path.dirname(os.path.abspath(__file__))214        module_name = "nrunner_%s" % self.kind.replace('-', '_')215        module_filename = '%s.py' % module_name216        if os.path.exists(os.path.join(core_dir, module_filename)):217            full_module_name = 'avocado.core.%s' % module_name218            candidate_cmd = [sys.executable, '-m', full_module_name]219            if self.is_kind_supported_by_runner_command(candidate_cmd):220                runners_registry[self.kind] = candidate_cmd221                return candidate_cmd222        # exhausted probes, let's save the negative on the cache and avoid223        # future similar problems224        runners_registry[self.kind] = False225    def pick_runner_class_from_entry_point(self):226        """Selects a runner class from entry points based on kind.227        This is related to the :data:`SpawnMethod.PYTHON_CLASS`. This228        complements the :data:`RUNNERS_REGISTRY_PYTHON_CLASS` on systems229        that have setuptools available.230        :returns: a class that inherits from :class:`BaseRunner` or None231        """232        if not PKG_RESOURCES_AVAILABLE:233            return234        namespace = 'avocado.plugins.runnable.runner'235        for ep in pkg_resources.iter_entry_points(namespace):236            if ep.name == self.kind:237                try:238                    obj = ep.load()239                    return obj240                except ImportError:241                    return242    def pick_runner_class(self, runners_registry=None):243        """Selects a runner class from the registry based on kind.244        This is related to the :data:`SpawnMethod.PYTHON_CLASS`245        :param runners_registry: a registry with previously registered246                                 runner classes, keyed by runnable kind247        :param runners_registry: dict248        :returns: a class that inherits from :class:`BaseRunner`249        :raises: ValueError if kind there's no runner from kind of runnable250        """251        if runners_registry is None:252            runners_registry = RUNNERS_REGISTRY_PYTHON_CLASS253        runner = runners_registry.get(self.kind, None)254        if runner is None:255            runner = self.pick_runner_class_from_entry_point()256        if runner is not None:257            return runner258        raise ValueError('Unsupported kind of runnable: %s' % self.kind)259class BaseRunner:260    """261    Base interface for a Runner262    """263    def __init__(self, runnable):264        self.runnable = runnable265    def prepare_status(self, status_type, additional_info=None):266        """Prepare a status dict with some basic information.267        This will add the keyword 'status' and 'time' to all status.268        :param: status_type: The type of event ('started', 'running',269                             'finished')270        :param: addional_info: Any additional information that you271                               would like to add to the dict. This must be a272                               dict.273        :rtype: dict274        """275        status = {'status': status_type,276                  'time': time.monotonic()}277        if isinstance(additional_info, dict):278            status.update(additional_info)279        return status280    def run(self):281        yield {}282class NoOpRunner(BaseRunner):283    """284    Sample runner that performs no action before reporting FINISHED status285    Runnable attributes usage:286     * uri: not used287     * args: not used288    """289    def run(self):290        yield self.prepare_status('started')291        yield self.prepare_status('finished', {'result': 'pass'})292RUNNERS_REGISTRY_PYTHON_CLASS['noop'] = NoOpRunner293class ExecRunner(BaseRunner):294    """295    Runner for standalone executables with or without arguments296    Runnable attributes usage:297     * uri: path to a binary to be executed as another process298     * args: arguments to be given on the command line to the299       binary given by path300     * kwargs: key=val to be set as environment variables to the301       process302    """303    def run(self):304        env = None305        if self.runnable.kwargs:306            current = dict(os.environ)307            current.update(self.runnable.kwargs)308            env = current309        if env and 'PATH' not in env:310            env['PATH'] = os.environ.get('PATH')311        process = subprocess.Popen(312            [self.runnable.uri] + list(self.runnable.args),313            stdin=subprocess.DEVNULL,314            stdout=subprocess.PIPE,315            stderr=subprocess.PIPE,316            env=env)317        yield self.prepare_status('started')318        most_current_execution_state_time = None319        while process.poll() is None:320            time.sleep(RUNNER_RUN_CHECK_INTERVAL)321            now = time.monotonic()322            if most_current_execution_state_time is not None:323                next_execution_state_mark = (most_current_execution_state_time +324                                             RUNNER_RUN_STATUS_INTERVAL)325            if (most_current_execution_state_time is None or326                    now > next_execution_state_mark):327                most_current_execution_state_time = now328                yield self.prepare_status('running')329        stdout = process.stdout.read()330        process.stdout.close()331        stderr = process.stderr.read()332        process.stderr.close()333        return_code = process.returncode334        yield self.prepare_status('finished', {'returncode': return_code,335                                               'stdout': stdout,336                                               'stderr': stderr})337RUNNERS_REGISTRY_PYTHON_CLASS['exec'] = ExecRunner338class ExecTestRunner(ExecRunner):339    """340    Runner for standalone executables treated as tests341    This is similar in concept to the Avocado "SIMPLE" test type, in which an342    executable returning 0 means that a test passed, and anything else means343    that a test failed.344    Runnable attributes usage is identical to :class:`ExecRunner`345    """346    def run(self):347        # Since Runners are standalone, and could be executed on a remote348        # machine in an "isolated" way, there is no way to assume a default349        # value, at this moment.350        skip_codes = self.runnable.config.get('runner.exectest.exitcodes.skip',351                                              [])352        for most_current_execution_state in super(ExecTestRunner, self).run():353            returncode = most_current_execution_state.get('returncode')354            if returncode in skip_codes:355                most_current_execution_state['result'] = 'skip'356            elif returncode == 0:357                most_current_execution_state['result'] = 'pass'358            else:359                most_current_execution_state['result'] = 'fail'360            yield most_current_execution_state361RUNNERS_REGISTRY_PYTHON_CLASS['exec-test'] = ExecTestRunner362class PythonUnittestRunner(BaseRunner):363    """364    Runner for Python unittests365    The runnable uri is used as the test name that the native unittest366    TestLoader will use to find the test.  A native unittest test367    runner (TextTestRunner) will be used to execute the test.368    Runnable attributes usage:369     * uri: a "dotted name" that can be given to Python standard370            library's :meth:`unittest.TestLoader.loadTestsFromName`371            method. While it's not enforced, it's highly recommended372            that this is "a test method within a test case class" within373            a test module.  Example is: "module.Class.test_method".374     * args: not used375     * kwargs: not used376    """377    @staticmethod378    def _uri_to_unittest_name(uri):379        if ':' in uri:380            module, class_method = uri.rsplit(':', 1)381        else:382            module = uri383            class_method = None384        if module.endswith('.py'):385            module = module[:-3]386        if module.startswith(os.path.curdir):387            module = module[1:]388            if module.startswith(os.path.sep):389                module = module[1:]390        module = module.replace(os.path.sep, ".")391        if class_method:392            return '%s.%s' % (module, class_method)393        return module394    @staticmethod395    def _run_unittest(uri, queue):396        sys.path.insert(0, ".")397        stream = io.StringIO()398        unittest_name = PythonUnittestRunner._uri_to_unittest_name(uri)399        suite = unittest.TestLoader().loadTestsFromName(unittest_name)400        runner = unittest.TextTestRunner(stream=stream, verbosity=0)401        unittest_result = runner.run(suite)402        if len(unittest_result.errors) > 0:403            result = 'error'404        elif len(unittest_result.failures) > 0:405            result = 'fail'406        elif len(unittest_result.skipped) > 0:407            result = 'skip'408        else:409            result = 'pass'410        stream.seek(0)411        output = {'status': 'finished',412                  'result': result,413                  'output': stream.read()}414        stream.close()415        queue.put(output)416    def run(self):417        if not self.runnable.uri:418            error_msg = 'uri is required but was not given'419            yield self.prepare_status('finished', {'result': 'error',420                                                   'output': error_msg})421            return422        queue = multiprocessing.SimpleQueue()423        process = multiprocessing.Process(target=self._run_unittest,424                                          args=(self.runnable.uri, queue))425        process.start()426        yield self.prepare_status('started')427        most_current_execution_state_time = None428        while queue.empty():429            time.sleep(RUNNER_RUN_CHECK_INTERVAL)430            now = time.monotonic()431            if most_current_execution_state_time is not None:432                next_execution_state_mark = (most_current_execution_state_time +433                                             RUNNER_RUN_STATUS_INTERVAL)434            if (most_current_execution_state_time is None or435                    now > next_execution_state_mark):436                most_current_execution_state_time = now437                yield self.prepare_status('running')438        status = queue.get()439        status['time'] = time.monotonic()440        yield status441RUNNERS_REGISTRY_PYTHON_CLASS['python-unittest'] = PythonUnittestRunner442def _parse_key_val(argument):443    key_value = argument.split('=', 1)444    if len(key_value) < 2:445        msg = ('Invalid keyword parameter: "%s". Valid option must '446               'be a "KEY=VALUE" like expression' % argument)447        raise argparse.ArgumentTypeError(msg)448    return tuple(key_value)449def _arg_decode_base64(arg):450    """451    Decode arguments possibly encoded as base64452    :param arg: the possibly encoded argument453    :type arg: str454    :returns: the decoded argument455    :rtype: str456    """457    prefix = 'base64:'458    if arg.startswith(prefix):459        content = arg[len(prefix):]460        return base64.decodebytes(content.encode()).decode()461    return arg462def _kwarg_decode_json(value):463    """464    Decode arguments possibly encoded as base64465    :param value: the possibly encoded argument466    :type value: str467    :returns: the decoded keyword argument as Python object468    """469    prefix = 'json:'470    if value.startswith(prefix):471        content = value[len(prefix):]472        return json.loads(content)473    return value474def _key_val_args_to_kwargs(kwargs):475    result = {}476    for key, val in kwargs:477        result[key] = _kwarg_decode_json(val)478    return result479class StatusEncoder(json.JSONEncoder):480    # pylint: disable=E0202481    def default(self, o):482        if isinstance(o, bytes):483            return {'__base64_encoded__': base64.b64encode(o).decode('ascii')}484        return json.JSONEncoder.default(self, o)485def json_dumps(data):486    return json.dumps(data, ensure_ascii=True, cls=StatusEncoder)487class TaskStatusService:488    """...runnable.py
Source:runnable.py  
...38    if value.startswith(prefix):39        content = value[len(prefix) :]40        return json.loads(content)41    return value42def _key_val_args_to_kwargs(kwargs):43    result = {}44    for key, val in kwargs:45        result[key] = _kwarg_decode_json(val)46    return result47class Runnable:48    """49    Describes an entity that be executed in the context of a task50    A instance of :class:`BaseRunner` is the entity that will actually51    execute a runnable.52    """53    def __init__(self, kind, uri, *args, config=None, **kwargs):54        if config is None:55            config = self.filter_runnable_config(kind, {})56        self.kind = kind57        #: The main reference to what needs to be run.  This is free58        #: form, but commonly set to the path to a file containing the59        #: test or being the test, or an actual URI with multiple60        #: parts61        self.uri = uri62        #: This attributes holds configuration from Avocado proper63        #: that is passed to runners, as long as a runner declares64        #: its interest in using them with65        #: attr:`avocado.core.nrunner.runner.BaseRunner.CONFIGURATION_USED`66        self._config = {}67        self.config = config or {}68        self.args = args69        self.tags = kwargs.pop("tags", None)70        self.dependencies = kwargs.pop("dependencies", None)71        self.variant = kwargs.pop("variant", None)72        self.output_dir = kwargs.pop("output_dir", None)73        self.kwargs = kwargs74        self._identifier_format = config.get("runner.identifier_format", "{uri}")75    def __repr__(self):76        fmt = (77            '<Runnable kind="{}" uri="{}" config="{}" args="{}" '78            'kwargs="{}" tags="{}" dependencies="{}"> variant="{}"'79        )80        return fmt.format(81            self.kind,82            self.uri,83            self.config,84            self.args,85            self.kwargs,86            self.tags,87            self.dependencies,88            self.variant,89        )90    @property91    def identifier(self):92        """Runnable identifier respecting user's format string.93        This is still experimental and we have room for improvements.94        This property it will return an unique identifier for this runnable.95        Please use this property in order to respect user's customization.96        By default runnables has its '{uri}' as identifier.97        Custom formatter can be configured and currently we accept the98        following values as normal f-strings replacements: {uri}, {args},99        and {kwargs}. "args" and "kwargs" are special cases.100        For args, since it is a list, you can use in two different ways:101        "{args}" for the entire list, or "{args[n]}" for a specific element102        inside this list.  The same is valid when using "{kwargs}". With103        kwargs, since it is a dictionary, you have to specify a key as index104        and then the values are used. For instance if you have a kwargs value105        named 'DEBUG', a valid usage could be: "{kwargs[DEBUG]}" and this will106        print the current value to this variable (i.e: True or False).107        Since this is formatter, combined values can be used. Example:108        "{uri}-{args}".109        """110        fmt = self._identifier_format111        # For the cases where there is no config (when calling the Runnable112        # directly113        if not fmt:114            return self.uri115        # For args we can use the entire list of arguments or with a specific116        # index.117        args = "-".join(self.args)118        if "args" in fmt and "[" in fmt:119            args = self.args120        # For kwargs we can use the entire list of values or with a specific121        # index.122        kwargs = "-".join(self.kwargs.values())123        if "kwargs" in fmt and "[" in fmt:124            kwargs = self.kwargs125        options = {"uri": self.uri, "args": args, "kwargs": kwargs}126        return fmt.format(**options)127    @property128    def config(self):129        return self._config130    @config.setter131    def config(self, config):132        """Sets the config values based on the runnable kind.133        This is not avocado config, it is a runnable config which is a subset134        of avocado config based on `STANDALONE_EXECUTABLE_CONFIG_USED` which135        describes essential configuration values for each runner kind.136        :param config: A config dict with new values for Runnable.137        :type config: dict138        """139        command = self.pick_runner_command(self.kind)140        if command is not None:141            command = " ".join(command)142            configuration_used = STANDALONE_EXECUTABLE_CONFIG_USED.get(command)143            if not set(configuration_used).issubset(set(config.keys())):144                LOG.warning(145                    "The runnable config should have only values "146                    "essential for its runner. In the next version of "147                    "avocado, this will raise a Value Error. Please "148                    "use avocado.core.nrunner.runnable.Runnable.filter_runnable_config "149                    "or avocado.core.nrunner.runnable.Runnable.from_avocado_config"150                )151        self._config = config152    @classmethod153    def from_args(cls, args):154        """Returns a runnable from arguments"""155        decoded_args = [_arg_decode_base64(arg) for arg in args.get("arg", ())]156        return cls.from_avocado_config(157            args.get("kind"),158            args.get("uri"),159            *decoded_args,160            config=json.loads(args.get("config", "{}"), cls=ConfigDecoder),161            **_key_val_args_to_kwargs(args.get("kwargs", [])),162        )163    @classmethod164    def from_recipe(cls, recipe_path):165        """166        Returns a runnable from a runnable recipe file167        :param recipe_path: Path to a recipe file168        :rtype: instance of :class:`Runnable`169        """170        with open(recipe_path, encoding="utf-8") as recipe_file:171            recipe = json.load(recipe_file)172        config = ConfigDecoder.decode_set(recipe.get("config", {}))173        return cls.from_avocado_config(174            recipe.get("kind"),175            recipe.get("uri"),...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
