<commit_before>"""
Functions for working with otu documents.

"""
import logging
from copy import deepcopy

import virtool.errors
import virtool.history
import virtool.utils

logger = logging.getLogger(__name__)



def evaluate_changes(data, document):
    name = data.get("name", None)
    abbreviation = data.get("abbreviation", None)
    schema = data.get("schema", None)

    if name == document["name"]:
        name = None

    old_abbreviation = document.get("abbreviation", "")

    if abbreviation == old_abbreviation:
        abbreviation = None

    if schema == document.get("schema", None):
        schema = None

    return name, abbreviation, schema


def extract_default_isolate(otu, isolate_processor=None):
    """
    Returns the default isolate dict for the given otu document.

    :param otu: a otu document.
    :type otu: dict

    :param isolate_processor: a function to process the default isolate into a desired format.
    :type: func

    :return: the default isolate dict.
    :rtype: dict

    """
    # Get the otu isolates with the default flag set to True. This list should only contain one item.
    default_isolates = [isolate for isolate in otu["isolates"] if isolate["default"] is True]

    if len(default_isolates) > 1:
        raise ValueError("More than one default isolate found")

    if len(default_isolates) == 0:
        raise ValueError("No default isolate found")

    default_isolate = default_isolates[0]

    if isolate_processor:
        default_isolate = isolate_processor(default_isolate)

    return default_isolate


def extract_default_sequences(joined):
    """
    Return a list of sequences from the default isolate of the passed joined otu document.

    :param joined: the joined otu document.
    :type joined: dict

    :return: a list of sequences associated with the default isolate.
    :rtype: list

    """
    for isolate in joined["isolates"]:
        if isolate["default"]:
            return isolate["sequences"]


def extract_isolate_ids(otu):
    """
    Get the isolate ids from a otu document.

    :param otu: a otu document.
    :return: a list of isolate ids.

    """
    return [isolate["id"] for isolate in otu["isolates"]]


def extract_sequence_ids(otu):
    """
    Extract all sequence ids from a merged otu.

    :param otu: the merged otu
    :type otu: dict

    :return: the sequence ids belonging to ``otu``
    :rtype: list

    """
    sequence_ids = list()

    isolates = otu["isolates"]

    if not isolates:
        raise ValueError("Empty isolates list in merged otu")

    for isolate in isolates:
        if "sequences" not in isolate:
            raise KeyError("Isolate in merged otu missing sequences field")

        if not isolate["sequences"]:
            raise ValueError("Empty sequences list in merged otu")

        sequence_ids += [sequence["_id"] for sequence in isolate["sequences"]]

    return sequence_ids


def find_isolate(isolates, isolate_id):
    """
    Return the isolate identified by ``isolate_id`` from a list of isolates.

    :param isolates: a list of isolate dicts
    :type isolates: list

    :param isolate_id: the isolate_id of the isolate to return
    :type isolate_id: str

    :return: an isolate
    :rtype: dict

    """
    return next((isolate for isolate in isolates if isolate["id"] == isolate_id), None)


def format_otu(joined, issues=False, most_recent_change=None):
    """
    Join the otu identified by the passed ``otu_id`` or use the ``joined`` otu document if available. Then,
    format the joined otu into a format that can be directly returned to API clients.

    :param joined:
    :type joined: Union[dict, NoneType]

    :param issues: an object describing issues in the otu
    :type issues: Union[dict, NoneType, bool]

    :param most_recent_change: a change document for the most recent change made to OTU
    :type most_recent_change: dict

    :return: a joined and formatted otu
    :rtype: dict

    """
    formatted = virtool.utils.base_processor(joined)

    del formatted["lower_name"]

    for isolate in formatted["isolates"]:

        for sequence in isolate["sequences"]:
            del sequence["otu_id"]
            del sequence["isolate_id"]

            sequence["id"] = sequence.pop("_id")

    formatted["most_recent_change"] = None

    if most_recent_change:
        formatted["most_recent_change"] = virtool.utils.base_processor(most_recent_change)

    formatted["issues"] = None

    if issues is False:
        formatted["issues"] = verify(joined)

    return formatted

<commit_msg>Fix unreturned OTU issues in API<commit_after>"""
Functions for working with otu documents.

"""
import logging
from copy import deepcopy

import virtool.errors
import virtool.history
import virtool.utils

logger = logging.getLogger(__name__)



def evaluate_changes(data, document):
    name = data.get("name", None)
    abbreviation = data.get("abbreviation", None)
    schema = data.get("schema", None)

    if name == document["name"]:
        name = None

    old_abbreviation = document.get("abbreviation", "")

    if abbreviation == old_abbreviation:
        abbreviation = None

    if schema == document.get("schema", None):
        schema = None

    return name, abbreviation, schema


def extract_default_isolate(otu, isolate_processor=None):
    """
    Returns the default isolate dict for the given otu document.

    :param otu: a otu document.
    :type otu: dict

    :param isolate_processor: a function to process the default isolate into a desired format.
    :type: func

    :return: the default isolate dict.
    :rtype: dict

    """
    # Get the otu isolates with the default flag set to True. This list should only contain one item.
    default_isolates = [isolate for isolate in otu["isolates"] if isolate["default"] is True]

    if len(default_isolates) > 1:
        raise ValueError("More than one default isolate found")

    if len(default_isolates) == 0:
        raise ValueError("No default isolate found")

    default_isolate = default_isolates[0]

    if isolate_processor:
        default_isolate = isolate_processor(default_isolate)

    return default_isolate


def extract_default_sequences(joined):
    """
    Return a list of sequences from the default isolate of the passed joined otu document.

    :param joined: the joined otu document.
    :type joined: dict

    :return: a list of sequences associated with the default isolate.
    :rtype: list

    """
    for isolate in joined["isolates"]:
        if isolate["default"]:
            return isolate["sequences"]


def extract_isolate_ids(otu):
    """
    Get the isolate ids from a otu document.

    :param otu: a otu document.
    :return: a list of isolate ids.

    """
    return [isolate["id"] for isolate in otu["isolates"]]


def extract_sequence_ids(otu):
    """
    Extract all sequence ids from a merged otu.

    :param otu: the merged otu
    :type otu: dict

    :return: the sequence ids belonging to ``otu``
    :rtype: list

    """
    sequence_ids = list()

    isolates = otu["isolates"]

    if not isolates:
        raise ValueError("Empty isolates list in merged otu")

    for isolate in isolates:
        if "sequences" not in isolate:
            raise KeyError("Isolate in merged otu missing sequences field")

        if not isolate["sequences"]:
            raise ValueError("Empty sequences list in merged otu")

        sequence_ids += [sequence["_id"] for sequence in isolate["sequences"]]

    return sequence_ids


def find_isolate(isolates, isolate_id):
    """
    Return the isolate identified by ``isolate_id`` from a list of isolates.

    :param isolates: a list of isolate dicts
    :type isolates: list

    :param isolate_id: the isolate_id of the isolate to return
    :type isolate_id: str

    :return: an isolate
    :rtype: dict

    """
    return next((isolate for isolate in isolates if isolate["id"] == isolate_id), None)


def format_otu(joined, issues=False, most_recent_change=None):
    """
    Join the otu identified by the passed ``otu_id`` or use the ``joined`` otu document if available. Then,
    format the joined otu into a format that can be directly returned to API clients.

    :param joined:
    :type joined: Union[dict, NoneType]

    :param issues: an object describing issues in the otu
    :type issues: Union[dict, NoneType, bool]

    :param most_recent_change: a change document for the most recent change made to OTU
    :type most_recent_change: dict

    :return: a joined and formatted otu
    :rtype: dict

    """
    formatted = virtool.utils.base_processor(joined)

    del formatted["lower_name"]

    for isolate in formatted["isolates"]:

        for sequence in isolate["sequences"]:
            del sequence["otu_id"]
            del sequence["isolate_id"]

            sequence["id"] = sequence.pop("_id")

    formatted["most_recent_change"] = None

    if most_recent_change:
        formatted["most_recent_change"] = virtool.utils.base_processor(most_recent_change)

    formatted["issues"] = issues or verify(joined)

    return formatted


{'fraction_non_alphanumeric': 0.0901612372490951, 'fraction_numerical': 0.0006581112207963146, 'mean_word_length': 3.1407811080835604, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2306567', 'n_tokens_mistral': 2803, 'n_tokens_neox': 2533, 'n_words': 933}