def _finalize()

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


    def _finalize(self):
        """
        The `_finalize` function is called once the last @card decorator calls `step_init`. Calling this function makes `current.card` ready for usage inside `@step` code.
        This function's works two parts :
        1. Resolving `self._default_editable_card`.
                - The `self._default_editable_card` holds the uuid of the card that will have access to the `append`/`extend` methods.
        2. Resolving edge cases where @card `id` argument may be `None` or have a duplicate `id` when there are more than one editable cards.
        3. Resolving the `self._default_editable_card` to the card with the`customize=True` argument.
        """
        all_card_meta = list(self._cards_meta.values())
        for c in all_card_meta:
            ct = get_card_class(c["type"])
            c["exists"] = False
            if ct is not None:
                c["exists"] = True

        # If a card has `customize=True` and is not editable then it will not be considered default editable.
        editable_cards_meta = [c for c in all_card_meta if c["editable"]]

        if len(editable_cards_meta) == 0:
            return

        # Create the `self._card_id_map` lookup table which maps card `id` to `uuid`.
        # This table has access to all cards with `id`s set to them.
        card_ids = []
        for card_meta in all_card_meta:
            if card_meta["card_id"] is not None:
                self._card_id_map[card_meta["card_id"]] = card_meta["uuid"]
                card_ids.append(card_meta["card_id"])

        # If there is only one editable card then this card becomes `self._default_editable_card`
        if len(editable_cards_meta) == 1:
            self._default_editable_card = editable_cards_meta[0]["uuid"]
            return

        # Segregate cards which have id as none and those which don't.
        not_none_id_cards = [c for c in editable_cards_meta if c["card_id"] is not None]
        none_id_cards = [c for c in editable_cards_meta if c["card_id"] is None]

        # If there is only 1 card with id set to None then we can use that as the default card.
        if len(none_id_cards) == 1:
            self._default_editable_card = none_id_cards[0]["uuid"]

        # If the size of the set of ids is not equal to total number of cards with ids then warn the user that we cannot disambiguate
        # so `current.card['my_card_id']` won't work.
        id_set = set(card_ids)
        if len(card_ids) != len(id_set):
            non_unique_ids = [
                idx
                for idx in id_set
                if len(list(filter(lambda x: x["card_id"] == idx, not_none_id_cards)))
                > 1
            ]
            nui = ", ".join(non_unique_ids)
            # throw a warning that decorators have non-unique Ids
            self._warning(
                (
                    "Multiple `@card` decorator have been annotated with duplicate ids : %s. "
                    "`current.card['%s']` will not work"
                )
                % (nui, non_unique_ids[0])
            )

            # remove the non unique ids from the `self._card_id_map`
            for idx in non_unique_ids:
                del self._card_id_map[idx]

        # if a @card has `customize=True` in the arguments then there should only be one @card with `customize=True`. This @card will be the _default_editable_card
        customize_cards = [c for c in editable_cards_meta if c["customize"]]
        if len(customize_cards) > 1:
            self._warning(
                (
                    "Multiple @card decorators have `customize=True`. "
                    "Only one @card per @step can have `customize=True`. "
                    "`current.card.append` will ignore all decorators marked `customize=True`."
                )
            )
        elif len(customize_cards) == 1:
            # since `editable_cards_meta` hold only `editable=True` by default we can just set this card here.
            self._default_editable_card = customize_cards[0]["uuid"]