コード例 #1
0
ファイル: native.py プロジェクト: wiwa/pants
    def generator_send(self, func, arg):
        """Given a generator, send it the given value and return a response."""
        if self._do_raise_keyboardinterrupt:
            raise KeyboardInterrupt("ctrl-c interrupted execution of a ffi method!")
        try:
            res = func.send(arg)

            if Get.isinstance(res):
                # Get.
                return self.lib.PyGeneratorResponseGet(
                    res.product_type, res.subject_declared_type, res.subject,
                )
            elif type(res) in (tuple, list):
                # GetMulti.
                return self.lib.PyGeneratorResponseGetMulti(
                    tuple(
                        self.lib.PyGeneratorResponseGet(
                            get.product_type, get.subject_declared_type, get.subject,
                        )
                        for get in res
                    )
                )
            else:
                raise ValueError(f"internal engine error: unrecognized coroutine result {res}")
        except StopIteration as e:
            if not e.args:
                raise
            # This was a `return` from a coroutine, as opposed to a `StopIteration` raised
            # by calling `next()` on an empty iterator.
            return self.lib.PyGeneratorResponseBreak(e.value)
コード例 #2
0
def run_rule(
    rule,
    *,
    rule_args: Optional[Sequence[Any]] = None,
    mock_gets: Optional[Sequence[MockGet]] = None,
    union_membership: Optional[UnionMembership] = None,
):
    """A test helper function that runs an @rule with a set of arguments and mocked Get providers.

    An @rule named `my_rule` that takes one argument and makes no `Get` requests can be invoked
    like so (although you could also just invoke it directly):

    ```
    return_value = run_rule(my_rule, rule_args=[arg1])
    ```

    In the case of an @rule that makes Get requests, things get more interesting: the
    `mock_gets` argument must be provided as a sequence of `MockGet`s. Each MockGet takes the Product
    and Subject type, along with a one-argument function that takes a subject value and returns a
    product value.

    So in the case of an @rule named `my_co_rule` that takes one argument and makes Get requests
    for a product type `Listing` with subject type `Dir`, the invoke might look like:

    ```
    return_value = run_rule(
      my_co_rule,
      rule_args=[arg1],
      mock_gets=[
        MockGet(
          product_type=Listing,
          subject_type=Dir,
          mock=lambda dir_subject: Listing(..),
        ),
      ],
    )
    ```

    If any of the @rule's Get requests involve union members, you should pass a `UnionMembership`
    mapping the union base to any union members you'd like to test. For example, if your rule has
    `await Get[TestResult](TargetAdaptor, target_adaptor)`, you may pass
    `UnionMembership({TargetAdaptor: PythonTestsTargetAdaptor})` to this function.

    :returns: The return value of the completed @rule.
    """

    task_rule = getattr(rule, "rule", None)
    if task_rule is None:
        raise TypeError(
            f"Expected to receive a decorated `@rule`; got: {rule}")

    if rule_args is not None and len(rule_args) != len(
            task_rule.input_selectors):
        raise ValueError(
            "Rule expected to receive arguments of the form: {}; got: {}".
            format(task_rule.input_selectors, rule_args))

    if mock_gets is not None and len(mock_gets) != len(task_rule.input_gets):
        raise ValueError(
            "Rule expected to receive Get providers for {}; got: {}".format(
                task_rule.input_gets, mock_gets))

    res = rule(*(rule_args or ()))
    if not isinstance(res, (CoroutineType, GeneratorType)):
        return res

    def get(product, subject):
        provider = next(
            (mock_get.mock
             for mock_get in mock_gets if mock_get.product_type == product and
             (mock_get.subject_type == type(subject) or
              (union_membership and union_membership.is_member(
                  mock_get.subject_type, subject)))),
            None,
        )
        if provider is None:
            raise AssertionError(
                "Rule requested: Get{}, which cannot be satisfied.".format(
                    (product, type(subject), subject)))
        return provider(subject)

    rule_coroutine = res
    rule_input = None
    while True:
        try:
            res = rule_coroutine.send(rule_input)
            if Get.isinstance(res):
                rule_input = get(res.product_type, res.subject)
            elif type(res) in (tuple, list):
                rule_input = [get(g.product_type, g.subject) for g in res]
            else:
                return res
        except StopIteration as e:
            if e.args:
                return e.value