Example #1
0
def parametrize(metafunc,
                argnames,
                argvalues,
                indirect=False,
                ids=None,
                scope=None,
                **kwargs):
    """
    This alternate implementation of metafunc.parametrize creates a list of calls that is not just the cartesian
    product of all parameters (like the pytest behaviour).

    Instead, it offers an alternate list of calls takinginto account all union fixtures.

    For this, it replaces the `metafunc._calls` attribute with a `CallsReactor` instance, and feeds it with all parameters
    and parametrized fixtures independently (not doing any cross-product).

    The resulting `CallsReactor` instance is then able to dynamically behave like the correct list of calls, lazy-creating
    that list when it is used.
    """
    # create our special container object if needed
    if not isinstance(metafunc._calls, CallsReactor):
        # first call: should be an empty list
        if len(metafunc._calls) > 0:
            raise ValueError("This should not happen - please file an issue")
        metafunc._calls = CallsReactor(metafunc)

    # grab it
    calls_reactor = metafunc._calls

    # detect union fixtures
    if is_fixture_union_params(argvalues):
        if ',' in argnames or not isinstance(argnames, string_types):
            raise ValueError("Union fixtures can not be parametrized")
        union_fixture_name = argnames
        union_fixture_alternatives = argvalues
        if indirect is False or len(kwargs) > 0:
            raise ValueError(
                "indirect cannot be set on a union fixture, as well as unknown kwargs"
            )

        # add a union parametrization in the queue (but do not apply it now)
        calls_reactor.append(
            UnionParamz(union_fixture_name, union_fixture_alternatives, ids,
                        scope, kwargs))
    else:
        # add a normal parametrization in the queue (but do not apply it now)
        calls_reactor.append(
            NormalParamz(argnames, argvalues, indirect, ids, scope, kwargs))
Example #2
0
    def _build_closure(
            self,
            fixture_defs_mgr,  # type: FixtureDefsCache
            initial_fixture_names  # type: Iterable[str]
    ):
        """

        :param arg2fixturedefs: set of fixtures already known by the parent node
        :return: nothing (the input arg2fixturedefs is modified)
        """

        # Grab all dependencies of all fixtures present at this node and add them to either this or to nodes below.

        # -- first switch this object from 'pending' to 'under construction' if needed
        # (indeed we now authorize and use the possibility to call this twice. see split() )
        if self.fixture_defs is None:
            self.fixture_defs = OrderedDict()

        # -- then for all pending, add them with their dependencies
        pending_fixture_names = list(initial_fixture_names)
        while len(pending_fixture_names) > 0:
            fixname = pending_fixture_names.pop(0)

            # if the fixture is already known in this node or above, do not care
            if self.already_knows_fixture(fixname):
                continue

            # else grab the fixture definition(s) for this fixture name for this test node id
            fixturedefs = fixture_defs_mgr.get_fixture_defs(fixname)
            if not fixturedefs:
                # fixture without definition: add it
                self.add_required_fixture(fixname, None)
            else:
                # the actual definition is the last one
                _fixdef = fixturedefs[-1]
                _params = _fixdef.params

                if _params is not None and is_fixture_union_params(_params):
                    # create an UNION fixture

                    # transform the _params into a list of names
                    alternative_f_names = UnionFixtureAlternative.to_list_of_fixture_names(
                        _params)

                    # if there are direct dependencies that are not the union members, add them to pending
                    non_member_dependencies = [
                        f for f in _fixdef.argnames
                        if f not in alternative_f_names
                    ]
                    pending_fixture_names += non_member_dependencies

                    # propagate WITH the pending
                    self.split_and_build(fixture_defs_mgr, fixname,
                                         fixturedefs, alternative_f_names,
                                         pending_fixture_names)

                    # empty the pending
                    pending_fixture_names = []

                else:
                    # normal fixture
                    self.add_required_fixture(fixname, fixturedefs)

                    # add all dependencies in the to do list
                    dependencies = _fixdef.argnames
                    # - append: was pytest default
                    # pending_fixture_names += dependencies
                    # - prepend: makes much more sense
                    pending_fixture_names = list(
                        dependencies) + pending_fixture_names