def update_card()

in metaflow/plugins/cards/card_cli.py [0:0]


def update_card(mf_card, mode, task, data, timeout_value=None):
    """
    This method will be responsible for creating a card/data-update based on the `mode`.
    There are three possible modes taken by this function.
        - render :
            - This will render the "final" card.
            - This mode is passed at task completion.
            - Setting this mode will call the `render` method of a MetaflowCard.
            - It will result in the creation of an HTML page.
        - render_runtime:
            - Setting this mode will render a card during task "runtime".
            - Setting this mode will call the `render_runtime` method of a MetaflowCard.
            - It will result in the creation of an HTML page.
        - refresh:
            - Setting this mode will refresh the data update for a card.
            - We support this mode because rendering a full card can be an expensive operation, but shipping tiny data updates can be cheap.
            - Setting this mode will call the `refresh` method of a MetaflowCard.
            - It will result in the creation of a JSON object.

    Parameters
    ----------
    mf_card : MetaflowCard
        MetaflowCard object which will be used to render the card.
    mode : str
        Mode of rendering the card.
    task : Task
        Task object which will be passed to render the card.
    data : dict
        object created and passed down from `current.card._get_latest_data` method.
        For more information on this object's schema have a look at `current.card._get_latest_data` method.
    timeout_value : int
        Timeout value for rendering the card.

    Returns
    -------
    CardRenderInfo
        - NamedTuple which will contain:
            - `mode`: The mode of rendering the card.
            - `is_implemented`: whether the function was implemented or not.
            - `data` : output from rendering the card (Can be string/dict)
            - `timed_out` : whether the function timed out or not.
            - `timeout_stack_trace` : stack trace of the function if it timed out.
    """

    def _add_token_html(html):
        if html is None:
            return None
        return html.replace(
            mf_card.RELOAD_POLICY_TOKEN,
            _extract_reload_token(data=data, task=task, mf_card=mf_card),
        )

    def _add_token_json(json_msg):
        if json_msg is None:
            return None
        return {
            "reload_token": _extract_reload_token(
                data=data, task=task, mf_card=mf_card
            ),
            "data": json_msg,
            "created_on": time.time(),
        }

    def _safe_call_function(func, *args, **kwargs):
        """
        returns (data, is_implemented)
        """
        try:
            return func(*args, **kwargs), True
        except NotImplementedError as e:
            return None, False

    def _call():
        if mode == "render":
            setattr(
                mf_card.__class__,
                "runtime_data",
                property(fget=lambda _, data=data: data),
            )
            output = _add_token_html(mf_card.render(task))
            return CardRenderInfo(
                mode=mode,
                is_implemented=True,
                data=output,
                timed_out=False,
                timeout_stack_trace=None,
            )

        elif mode == "render_runtime":
            # Since many cards created by metaflow users may not have implemented a
            # `render_time` / `refresh` methods, it can result in an exception and thereby
            # creation of error cards (especially for the `render_runtime` method). So instead
            # we will catch the NotImplementedError and return None if users have not implemented it.
            # If there any any other exception from the user code, it should be bubbled to the top level.
            output, is_implemented = _safe_call_function(
                mf_card.render_runtime, task, data
            )
            return CardRenderInfo(
                mode=mode,
                is_implemented=is_implemented,
                data=_add_token_html(output),
                timed_out=False,
                timeout_stack_trace=None,
            )

        elif mode == "refresh":
            output, is_implemented = _safe_call_function(mf_card.refresh, task, data)
            return CardRenderInfo(
                mode=mode,
                is_implemented=is_implemented,
                data=_add_token_json(output),
                timed_out=False,
                timeout_stack_trace=None,
            )

    render_info = None
    if timeout_value is None or timeout_value < 0:
        return _call()
    else:
        try:
            with timeout(timeout_value):
                render_info = _call()
        except TimeoutError:
            stack_trace = traceback.format_exc()
            return CardRenderInfo(
                mode=mode,
                is_implemented=True,
                data=None,
                timed_out=True,
                timeout_stack_trace=stack_trace,
            )
        return render_info