Source code for bridge.pipelines.gh2bt_for_meta.map_funcs.topic

"""
Mapping GitHub topics to bio.tools EDAM topics.

This module aligns GitHub repository topics with bio.tools EDAM topics.
It compares the list of topics reported by GitHub for a repository with the list of
existing bio.tools EDAM topics and applies a reconciliation policy that prefers GitHub
topics when they are present, while retaining existing bio.tools topics.
"""

from bridge.builders import compose_edam_term_metadata
from bridge.core import EDAMTerm
from bridge.core.biotools import TopicItem
from bridge.logging import get_user_logger
from bridge.pipelines.policies.gh2bt import reconcile_gh_ontop_bt

logger = get_user_logger()


def _to_topic_set_gh(gh_topics: list[str] | None) -> set[str] | None:
    """
    Normalize GitHub topics to a lowercased string set.

    Parameters
    ----------
    gh_topics : list[str] | None
        List of GitHub topics, or ``None`` if no topics are present.

    Returns
    -------
    set[str] | None
        A set of lowercased GitHub topic names, or ``None`` if no topics are provided.
    """
    if not gh_topics:
        return None
    return {topic.lower() for topic in gh_topics}


def _to_topic_set_bt(bt_topics: list[TopicItem] | None) -> set[str] | None:
    """
    Normalize bio.tools EDAM topics to a lowercased string set.

    Parameters
    ----------
    bt_topics : list[TopicItem] | None
        List of bio.tools EDAM topic annotations, or ``None`` if no topics are recorded.

    Returns
    -------
    set[str] | None
        A set of lowercased topic names derived from the `TopicItem` values, or ``None`` if no topics are recorded.
    """
    if not bt_topics:
        return None
    return {topic.term.lower() for topic in bt_topics}


async def _cast_to_biotools_topics(topics: set[str]) -> list[TopicItem] | None:
    """
    Cast a set of topic strings to a list of EDAM topics by looking up corresponding EDAM terms.

    Parameters
    ----------
    topics : set[str]
        A set of lowercased topic names.

    Returns
    -------
    list[TopicItem] | None
        A list of `TopicItem` enum members corresponding to the input topic names,
        or ``None`` if no valid topics are found.
    """
    bt_topics: list[TopicItem] = []
    for topic in topics:
        try:
            edam_term: EDAMTerm = await compose_edam_term_metadata(topic)
            if not edam_term or not edam_term.label or not edam_term.iri:
                logger.note(f"GitHub topic '{topic}' could not be resolved to a valid EDAM term and will be skipped.")
                continue
            matched_topic = TopicItem(term=edam_term.label, uri=edam_term.iri)
            logger.added(
                f"Mapped GitHub topic '{topic}' to bio.tools EDAM topic "
                f"'{matched_topic.term}' with URI '{matched_topic.uri}'.",
            )
            bt_topics.append(matched_topic)
        except Exception as e:
            logger.note(f"Error retrieving EDAM term for GitHub topic '{topic}': {e}. This topic will be skipped.")
            continue

    return bt_topics or None


[docs] async def map_topics(gh_topics: list[str] | None, bt_topics: list[TopicItem] | None) -> list[TopicItem] | None: """ Map and reconcile GitHub topics with bio.tools EDAM topics using the generic GitHub-over-bio.tools policy. GitHub topics are normalized to a lowercased set of strings, and bio.tools topics are similarly normalized to a set of lowercased topic names derived from the `TopicItem` enum members. Parameters ---------- gh_topics : list[str] | None List of GitHub topics, or ``None`` if no topics are present. bt_topics : list[TopicItem] | None List of existing bio.tools EDAM topic annotations, or ``None`` if no topics are recorded. Returns ------- list[TopicItem] | None A reconciled list of `TopicItem` enum members representing the topics for the tool, preferring GitHub topics when available, or ``None`` if no topics can be determined """ gh_norm = _to_topic_set_gh(gh_topics) bt_norm = _to_topic_set_bt(bt_topics) return await reconcile_gh_ontop_bt( gh_norm=gh_norm, bt_norm=bt_norm, bt_value=bt_topics, build_bt_from_gh=None, build_bt_from_norm=lambda bt_norm: _cast_to_biotools_topics(bt_norm), log_label="topics", )