Esempio n. 1
0
def test_kwargs_passed_to_default_path(foo, logger, event, **kwargs):
    try:
        assert foo == "bar"
    except AssertionError as e:
        raise FailButContinue("foo was not set to bar") from e
Esempio n. 2
0
def execute_payload(
    payload: Payload,
    path_enum: EnumMeta,
    paths: dict,
    logger,
    event,
    context,
    debug=False,
):
    """Execute functions, paths, and shortcuts in a Path.

    Args:
        payload (Payload):
        path_enum (EnumMeta): An Enum class which define the possible paths available in this lambda.
        paths (dict): Keys are path names / enums and values are a list of Action objects
        logger:
        event: https://docs.aws.amazon.com/lambda/latest/dg/python-handler.html
        context: https://docs.aws.amazon.com/lambda/latest/dg/python-handler.html
    """
    if not logger:
        logger = ServerlessLogger()

    ret = None

    if not isinstance(payload.path, path_enum):
        payload.path = clean_path(path_enum, payload.path)

    if isinstance(payload.path, Enum):  # PATH
        # Allow someone to simplify their definition of a Path to a list of functions.
        if all([isinstance(f, FunctionType) for f in paths[payload.path]]):
            paths[payload.path] = [Action(functions=action)]

        for action in paths[payload.path]:
            assert isinstance(action, Action)

            # Build action kwargs and validate type hints
            try:
                dummy = ["logger", "event"]
                action_kwargs = build_action_kwargs(action, {
                    **{k: None
                       for k in dummy},
                    **payload.kwargs
                })
                for k in dummy:
                    action_kwargs.pop(k, None)
            except (TypeError, AssertionError) as e:
                raise InvalidPayloadError(
                    f"Failed to run {payload.path.name} {action} due to {exception_to_str(e)}"
                ) from e

            # Run action functions
            for f in action.functions:
                assert isinstance(f, FunctionType)
                try:
                    # TODO: if ret, set _last_output
                    _log_context = {
                        "path": payload.path.name,
                        "function": f.__name__
                    }
                    with logger.context(bind={
                            **_log_context, "kwargs": action_kwargs
                    }):
                        logger.log("Executing function.")
                    with logger.context(bind=_log_context):
                        ret = f(
                            **{
                                **action_kwargs,
                                "logger": logger,
                                "event": {
                                    "event": event,
                                    "context": context,
                                    "payload": payload,
                                },
                            })

                    if ret:
                        _payloads = []
                        try:
                            if isinstance(ret, Payload):
                                _payloads.append(ret.validate(path_enum))
                            elif isinstance(ret, list):
                                for r in ret:
                                    if isinstance(r, Payload):
                                        _payloads.append(r.validate(path_enum))
                        except Exception as e:
                            logger.debug(exception_to_str(e))
                            raise FailButContinue(
                                f"Something went wrong while extracting Payloads from a function return value. {ret}"
                            ) from e

                        for p in _payloads:
                            logger.debug(
                                f"Function returned a Payload. Executing. {p}")
                            try:
                                ret = execute_payload(p, path_enum, paths,
                                                      logger, event, context,
                                                      debug)
                            except Exception as e:
                                logger.debug(exception_to_str(e))
                                raise FailButContinue(
                                    f"Failed to execute returned Payload. {p}"
                                ) from e
                except LpipeBaseException:
                    # CAPTURES:
                    #    FailButContinue
                    #    FailCatastrophically
                    raise
                except Exception as e:
                    logger.error(
                        f"Skipped {payload.path.name} {f.__name__} due to unhandled Exception. This is very serious; please update your function to handle this. Reason: {exception_to_str(e)}"
                    )
                    sentry.capture(e)
                    if debug:
                        raise FailCatastrophically() from e

            # Run action paths / shortcuts
            for path_descriptor in action.paths:
                _payload = Payload(
                    clean_path(path_enum, path_descriptor),
                    action_kwargs,
                    payload.event_source,
                ).validate(path_enum)
                ret = execute_payload(_payload, path_enum, paths, logger,
                                      event, context, debug)
    elif isinstance(payload.path, Queue):  # SHORTCUT
        queue = payload.path
        assert isinstance(queue.type, QueueType)
        with logger.context(
                bind={
                    "path": queue.path,
                    "queue_type": queue.type,
                    "queue_name": queue.name,
                    "kwargs": payload.kwargs,
                }):
            logger.log("Pushing record.")
        put_record(queue=queue,
                   record={
                       "path": queue.path,
                       "kwargs": payload.kwargs
                   })
    else:
        logger.info(
            f"Path should be a string (path name), Path (path Enum), or Queue: {payload.path})"
        )

    return ret
Esempio n. 3
0
def test_kwargs_passed_to_default_path_include_all(logger, event, **kwargs):
    try:
        assert kwargs.get("foo", None) == "bar"
    except AssertionError as e:
        raise FailButContinue("foo was not set to bar") from e